找到了与请求匹配的多个操作

我已经阅读了很多关于路由和控制器的问题,但我找不到我想要的东西。 我有这个结构的控制器:

更新:包含完整的类源。

public class LocationsController : ApiController { private readonly IUnitOfWork _unitOfWork; public LocationsController(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; } // GET /api/locations/id public Location Get(Guid id) { return this.QueryById(id, _unitOfWork); } // GET /api/locations public IQueryable Get() { return this.Query(_unitOfWork); } // POST /api/locations public HttpResponseMessage Post(Location location) { var id = _unitOfWork.CurrentSession.Save(location); _unitOfWork.Commit(); var response = Request.CreateResponse(HttpStatusCode.Created, location); response.Headers.Location = new Uri(Request.RequestUri, Url.Route(null, new { id })); return response; } // PUT /api/locations public Location Put(Location location) { var existingLocation = _unitOfWork.CurrentSession.Query().SingleOrDefault(x => x.Id == location.Id); //check to ensure update can occur if (existingLocation == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } //merge detached entity into session _unitOfWork.CurrentSession.Merge(location); _unitOfWork.Commit(); return location; } // DELETE /api/locations/5 public HttpResponseMessage Delete(Guid id) { var existingLocation = _unitOfWork.CurrentSession.Query().SingleOrDefault(x => x.Id == id); //check to ensure delete can occur if (existingLocation != null) { _unitOfWork.CurrentSession.Delete(existingLocation); _unitOfWork.Commit(); } return new HttpResponseMessage(HttpStatusCode.NoContent); } // rpc/locations public HttpResponseMessage Dummy() { // I use it to generate some random data to fill the database in a easy fashion Location location = new Location(); location.Latitude = RandomData.Number.GetRandomDouble(-90, 90); location.Longitude = RandomData.Number.GetRandomDouble(-180, 180); location.Name = RandomData.LoremIpsum.GetSentence(4, false); var id = _unitOfWork.CurrentSession.Save(location); _unitOfWork.Commit(); var response = Request.CreateResponse(HttpStatusCode.Created, location); response.Headers.Location = new Uri(Request.RequestUri, Url.Route(null, new { id })); return response; } } 

和我的路由定义(Global.asax):

 public static void RegisterRoutes(RouteCollection routes) { // Default route routes.MapHttpRoute( name: "Default", routeTemplate: "{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); // A route that enables RPC requests routes.MapHttpRoute( name: "RpcApi", routeTemplate: "rpc/{controller}/{action}", defaults: new { action = "Get" } ); } 

到目前为止,如果我点击浏览器:

  • [baseaddress]/locations/s0m3-gu1d-g0e5-hee5eeeee //有效
  • [baseaddress]/locations/ //找到多个结果
  • [baseaddress]/rpc/locations/dummy //有效

最奇怪的是, 这曾经起作用 ,直到我在执行一些更新时弄乱了我的NuGet。 我在这里想念的是什么?

以GET,POST,PUT或delete开头的动词将自动转到第一个路径,我的虚拟测试方法将通过rpc调用,这将落入第二个路径。

抛出的错误是带有消息的InvalidOperationException

找到了与请求匹配的多个操作:System.Linq.IQueryable`1 [Myproject.Domain.Location]类型Myproject.Webservices.Controllers.LocationsController上的Get()System.Net.Http.HttpResponseMessage类型为Myproject.Webservices的Dummy() .Controllers.LocationsController

有任何想法吗?

问题在于加载路由的顺序。 如果它们是这样的:

 // A route that enables RPC requests routes.MapHttpRoute( name: "RpcApi", routeTemplate: "rpc/{controller}/{action}", defaults: new { action = "Get" } ); // Default route routes.MapHttpRoute( name: "Default", routeTemplate: "{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); 

它会工作正常。 首先,请求将映射到RPC,然后映射到控制器(可能有或没有Id)。

我们还可以为Api控制器创建自定义动作选择器,如下所示,这样可以使用传统的“GET,POST,PUT,DELETE”自由地处理复杂类型:

  class ApiActionSelector : IHttpActionSelector { private readonly IHttpActionSelector defaultSelector; public ApiActionSelector(IHttpActionSelector defaultSelector) { this.defaultSelector = defaultSelector; } public ILookup GetActionMapping(HttpControllerDescriptor controllerDescriptor) { return defaultSelector.GetActionMapping(controllerDescriptor); } public HttpActionDescriptor SelectAction(HttpControllerContext controllerContext) { // Get HttpMethod from current context HttpMethod httpMethod = controllerContext.Request.Method; // Set route values for API controllerContext.RouteData.Values.Add("action", httpMethod.Method); // Invoke Action return defaultSelector.SelectAction(controllerContext); } } 

我们可以在WebApiConfig中注册相同的内容:

  config.Services.Replace(typeof(IHttpActionSelector), new ApiActionSelector(config.Services.GetActionSelector())); 

可以帮助运行此类问题的用户。