使用FiveLevelsOfMediaType(5LMT)的基于内容的操作选择Web API不起作用

时间:2015-05-05 16:42:19

标签: c# asp.net-mvc-routing asp.net-web-api asp.net-web-api-routing

我试图实现一个使用命令来改变系统状态的RESTful API(基于CQRS策略)。默认情况下,Web API的路由将难以与基于检查对象参数类型的操作匹配。为了解决这个问题,我一直在使用以下指南: Content Based Action Selection Using Five Levels of Media Type

按照说明操作后,它仍会导致模糊的匹配异常,这是由我的控制器中重载的Put方法引起的。

我的WebApiConfig如下:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
        );

        config.AddFiveLevelsOfMediaType();
    }
}

我的控制器如下:

public class ProductsController : ApiController
{
    public ProductDTO Get(int id)
    {
        var query = new ProductByIdQuery { Id = id };
        ProductDTO product = _queryBus.Dispatch(query);
        return product;
    }

    public void Put(ChangeProductCodeCommand command)
    {
        _commandBus.Dispatch(command);
    }

    public void Put(SetProductParentCommand command)
    {
        _commandBus.Dispatch(command);
    }

    public ProductsController(IQueryBus queryBus, ICommandBus commandBus)
    {
        _queryBus = queryBus;
        _commandBus = commandBus;
    }

    IQueryBus _queryBus;
    ICommandBus _commandBus;
}

在客户端,我发送的http标头是:

PUT /api/products HTTP/1.1
Content-Type: application/json;domain-model=ChangeProductCodeCommand

JSON:

{
  ProductId: 758,
  ProductCode: "TEST"
}

结果:

{
  "Message": "An error has occurred.",
  "ExceptionMessage": "Ambiguous Match",
  "ExceptionType": "System.InvalidOperationException",
  "StackTrace": "   at       ApiActionSelection.System.Web.Http.Controllers.ApiActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n   at ApiActionSelection.System.Web.Http.Controllers.ApiActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n   at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}

为什么这不起作用的任何想法?

1 个答案:

答案 0 :(得分:2)

有两个Put方法只有参数类型不同,Web API会尝试根据传入参数的类型解析为正确的操作。

除非默认模型绑定器可以将传入的JSON映射到您已实现的复杂类型,并且该类型与您的Put方法之一的参数类型匹配,否则Web API将使用{{1}进行响应您看到的异常,因为它无法确定要调用的方法。请注意,默认情况下,Web API不会在行动解决方案中使用您的"Ambiguous Match"标题。

我建议您阅读Routing and Action Selection in ASP.NET Web API,以便了解路由在内部的运作方式。然后,您可能希望创建自己的Content-Type实现,在其中检查IHttpActionSelector,并将请求路由到您选择的操作。您可以找到示例实现here

您还可以阅读有关模型绑定here的更多信息,以了解如何将传入的JSON解析为您的某个类型。