向WebAPI添加新方法可以提供多个操作"错误

时间:2016-03-08 10:17:22

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

我有一个现有的WebAPI 2项目,它有当前的路由:

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

控制器由通用基本控制器和每个"实体类型的派生控制器组成。实施 路线:

[GET] api/{entity}/  <- returns an overview list of entities
[GET] api/{entity}/{id} <-  returns the full entity + details
[POST] api/{entity}/{id} <- saves the entity
[DEL] api/{entity}/{id} <- deletes the entity
[POST] api/{entity}/ <- creates a new entity
[POST] api/{entity}/{id}/{function} <- performs a function on an entity (eg. recalculate, send orders,..) 

现在我想为我的basecontroller添加一个新方法,以便能够获得&#34; count&#34;获取概述清单。所以基本上

[GET] api/{entity}/count

我已将以下路由添加到webapi配置中:

config.Routes.MapHttpRoute
(
    name: "count",
    routeTemplate: "api/{controller}/", defaults: new { action = "count" }
);

并向我的控制器添加了一个方法:

[HttpGet]
public async Task<int> Count()
{
    return 5;//just a fixed testvalue
}

如果我现在浏览/api/{entity}/count,我会得到值&#34; 5&#34;回。 但问题是概述列表/api/{entity}/不再有效。它说:

ExceptionMessage: "Multiple actions were found that match the request"

我已尝试使用&#34; Route&#34;属性和路由的顺序,但我无法得到它(这是:一切都像以前一样工作+在API中添加&#34; count&#34;)。我也在SO上找了解并发现How to add custom methods to ASP.NET WebAPI controller?之类的线索,但我仍然无法工作:(

有什么想法吗?

日Thnx。

3 个答案:

答案 0 :(得分:0)

这是因为/{id}/{function}被定义为API路线的可选参数,两条路线都与提供的网址相匹配。

没有必要定义另一个路径,只需在控制器中定义方法并用[HttpGet]属性装饰它,你应该没问题。

答案 1 :(得分:0)

在未指定/ count时,您为计数操作配置的新路由与system.url-prefix冲突。

您可以移除新路线并使用默认[GET] api/{entity}/,当您拨打网址/api/{controller}/{action}

时,会调用您的计数方法

答案 2 :(得分:0)

经过大量的搜索,我已经制定了以下不需要任何新路线的解决方案 根据我的搜索,它更“RESTfull”。

我选择了/api{entity}?count查询参数并在响应标头“X-Total-Count”中传递计数。

但问题是,我现有的GET方法已经返回了一个我不能改变的Generic IList 没有打破API。我也不能只返回一个“对象”,它是一个列表或int,取决于是否 提供了“count”查询参数,因为它打破了Swagger文档(它不再看到返回类型)

我创建了一个新类CountList:

公共接口IHasCount     {         int TotalCount {get; }     }

public class CountList<T> : List<T>, IHasCount
{
    public int TotalCount { get; set; }

    public CountList(int count)
    {
        TotalCount = count;
    } 

    public CountList(IList<T> list )
    {
        this.AddRange(list);
        this.TotalCount = list.Count;
    }
}

继承List的一个很好的副作用是在json序列化过程中剥离了额外的信息 所以我可以安全地返回一个Countlist而不是List,而现有的客户现在不会有差别!

然后,为了从Countlist中提取计数并将其放入响应头,我做了一个小动作过滤器:

public class GetCountFilter : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        base.OnActionExecuted(actionExecutedContext);
        var counter = (actionExecutedContext.ActionContext.Response.Content as ObjectContent)?.Value as IHasCount;
        if (counter != null)
            actionExecutedContext.ActionContext.Response.Headers.Add("X-Total-Count", counter.TotalCount.ToString());
    }
}

然后我装饰了我的Get方法:

    [HttpGet]
    [GetCountFilter]
    public async Task<CountList<T>> GetOverview()
    {
        //special case, we only need the count !
        if (ServerContext.QueryFilter.CountOnly) //custom object that parses the queryParameters
        {
            //todo, but out of scope here,, make a real Count method in the manager that actually executes a count query instead of fetching the whole list
            var count = (await _entityManager.GetOverview()).Count; 
            var result = new CountList<T>(count);
            return result;
        }
        //return the full list
        return new CountList<T>( await _entityManager.GetOverview());
    }

所以,作为一个结果,当一个客户调用/api/{entity}时,他像往常一样得到概述,并附加了 填写了X-Total-Count标头。 当他调用/api/{entity}?count时,他会得到一个空列表,但总计数仍在标题中!

这对我有用!如果我完全没有在房间里看到大象,请告诉我!