Web API 通用操作

Jef*_*son 7 .net c# asp.net asp.net-web-api

我有一个需要接受两个不同对象模型的 http 操作。实现查看两个模型对象并知道此时该做什么。我可以使用通用对象吗?

[HttpPost]
public IHttpActionResult InsertData(string accessKey, [FromBody] T content)
{
    try
    {
        MobileAppService ms = new MobileAppService();
        ResultStatus resultStatus = ms.ProcessAppLogging(t);
        return Ok(resultStatus.ResultCode);
    }
    catch (Exception e)
    {
        Elmah.ErrorSignal.FromCurrentContext().Raise(e);
    }
}
Run Code Online (Sandbox Code Playgroud)

Rez*_*aei 11

具有通用操作方法的控制器

使用框架的默认实现,不,你不能有这样的操作:

public IHttpActionResult InsertData([FromBody] T model)
Run Code Online (Sandbox Code Playgroud)

这是您收到的例外情况:

无法在控制器“XXXX”上调用操作方法“XXXX”,因为操作方法是通用方法。

但是这个框架是非常可扩展的,如果你对ASP.NET Web API 中的路由和操作选择有很好的理解并了解路由、控制器选择、操作选择、参数绑定和操作调用的工作原理,那么您可以实现一些自定义支持通用操作方法选择和调用的框架。

在您的自定义逻辑中,为了能够在运行时执行操作,您需要T在运行时解析。为此,您可以依靠属性将其限制为某些已知类型,或者您可以依靠某些上下文信息,例如路由数据、标头值、一些特殊值,例如$type正文等)。

提供自定义实现来处理通用操作方法对于这篇文章来说太宽泛了。也就是说,让我分享其他解决方案。

从通用基本控制器派生

您可以拥有一个基本通用控制器,然后有两个从基本控制器派生的非通用控制器,并通过在基本控制器中实现的单个方法处理请求。我假设您已经看过这篇文章,它已经提出了相同的解决方案:

public class MyBaseController<T> : ApiController
{
    public IHttpActionResult InsertData([FromBody] T model)
    {
        //Write the generic code here, for example:
        dbContext.Set<T>().Add(model);
        dbContext.SaveChanges();
        return some value;            
    }
}
Run Code Online (Sandbox Code Playgroud)

然后:

public class ProductController : MyBaseController<Product> { }
public class CustomerController : MyBaseController<Customer> { }
Run Code Online (Sandbox Code Playgroud)

dynamic稍后根据上下文信息依赖并解析类型

另一种选择是使用以下操作方法:

public IHttpActionResult InsertData([FromBody] dynamic model)
Run Code Online (Sandbox Code Playgroud)

然后根据一些上下文信息(如路由值、标头值、一些特殊值(如$typebody 等)),您可以解析模型类型并调用您的私有泛型方法:

public IHttpActionResult InsertData([FromBody] dynamic model)
{
    Type t = resolve type base on context information
    object data = create an instance of t base on the model values;

    var method = this.GetType().GetMethod(nameof(InsertDataPrivate),
        BindingFlags.NonPublic | BindingFlags.Instance);
    var result = (int)method.MakeGenericMethod(t)
       .Invoke(this, new object[] { data });

    return Ok(result);
}
private int InsertDataPrivate<T>(T model) where T
{
    //Write the generic code here, for example:
    dbContext.Set<T>().Add(model);
    dbContext.SaveChanges();
    return some value;
}
Run Code Online (Sandbox Code Playgroud)