我已经阅读了很多关于路由和控制器的问题,但我根本无法找到我正在寻找的东西。我有这个结构的控制器:
更新:包含全班来源。
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<Location>(id, _unitOfWork);
}
// GET /api/locations
public IQueryable<Location> Get()
{
return this.Query<Location>(_unitOfWork);
}
// POST /api/locations
public HttpResponseMessage Post(Location location)
{
var id = _unitOfWork.CurrentSession.Save(location);
_unitOfWork.Commit();
var response = Request.CreateResponse<Location>(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<Location>().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<Location>().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<Location>(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.Controllers.LocationsController的Dummy()
有什么想法吗?
答案 0 :(得分:5)
问题在于路由加载的顺序。如果它们是这样的:
// 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)。
答案 1 :(得分:0)
我们还可以为Api控制器创建自定义动作选择器,如下所示,这样就可以使用传统的&#34; GET,POST,PUT,DELETE&#34;自由地处理复杂类型:
class ApiActionSelector : IHttpActionSelector
{
private readonly IHttpActionSelector defaultSelector;
public ApiActionSelector(IHttpActionSelector defaultSelector)
{
this.defaultSelector = defaultSelector;
}
public ILookup<string, HttpActionDescriptor> 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()));
可以帮助运行此类问题的用户。