ASP.NET Web API中具有多个GET方法的单个控制器

在Web API中,我有一类相似的结构:

public class SomeController : ApiController { [WebGet(UriTemplate = "{itemSource}/Items")] public SomeValue GetItems(CustomParam parameter) { ... } [WebGet(UriTemplate = "{itemSource}/Items/{parent}")] public SomeValue GetChildItems(CustomParam parameter, SomeObject parent) { ... } } 

由于我们可以映射单个方法,因此在正确的位置获得正确的请求非常简单。 对于只有一个GET方法但也有一个Object参数的类,我成功地使用了IActionValueBinder 。 但是,在上述情况下,我得到以下错误:

 Multiple actions were found that match the request: SomeValue GetItems(CustomParam parameter) on type SomeType SomeValue GetChildItems(CustomParam parameter, SomeObject parent) on type SomeType 

我试图通过重写ApiControllerExecuteAsync方法来解决这个问题,但目前为止没有运气。 有关这个问题的任何build议?

编辑:我忘了提到,现在我正试图移动ASP.NET Web API,这有不同的方法路由的代码。 问题是,如何使代码在ASP.NET Web API上工作?

这是我发现支持额外的GET方法并支持正常的REST方法的最好方法。 将以下路由添加到您的WebApiConfig中:

 routes.MapHttpRoute("DefaultApiWithId", "Api/{controller}/{id}", new { id = RouteParameter.Optional }, new { id = @"\d+" }); routes.MapHttpRoute("DefaultApiWithAction", "Api/{controller}/{action}"); routes.MapHttpRoute("DefaultApiGet", "Api/{controller}", new { action = "Get" }, new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) }); routes.MapHttpRoute("DefaultApiPost", "Api/{controller}", new {action = "Post"}, new {httpMethod = new HttpMethodConstraint(HttpMethod.Post)}); 

我用下面的testing类validation了这个解决scheme。 我能够成功地击中我的控制器中的每个方法:

 public class TestController : ApiController { public string Get() { return string.Empty; } public string Get(int id) { return string.Empty; } public string GetAll() { return string.Empty; } public void Post([FromBody]string value) { } public void Put(int id, [FromBody]string value) { } public void Delete(int id) { } } 

我证实它支持以下请求:

 GET /Test GET /Test/1 GET /Test/GetAll POST /Test PUT /Test/1 DELETE /Test/1 

请注意 ,如果额外的GET操作不以“Get”开头,则可能需要为该方法添加HttpGet属性。

从这里开始:

 config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}", new { id = RouteParameter.Optional }); 

对此:

 config.Routes.MapHttpRoute("API Default", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional }); 

因此,你现在可以指定你要发送HTTP请求的动作(方法)。

张贴到“http:// localhost:8383 / api / Command / PostCreateUser”调用:

 public bool PostCreateUser(CreateUserCommand command) { //* ... *// return true; } 

并发布到“http:// localhost:8383 / api / Command / PostMakeBooking”调用:

 public bool PostMakeBooking(MakeBookingCommand command) { //* ... *// return true; } 

我在一个自我托pipe的WEB API服务应用程序中尝试过,它的作用就像一个魅力:)

我发现属性比通过代码手动添加属性更清晰。 这是一个简单的例子。

 [RoutePrefix("api/example")] public class ExampleController : ApiController { [HttpGet] [Route("get1/{param1}")] // /api/example/get1/1?param2=4 public IHttpActionResult Get(int param1, int param2) { Object example = null; return Ok(example); } } 

你也需要这个在你的webapiconfig

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

一些好的链接http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api这个解释路由更好。; http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

您需要像这样在global.asax.cs中定义更多的路由:

 routes.MapHttpRoute( name: "Api with action", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); 

我不知道你是否find了答案,但我做到了,它的工作原理

 public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // GET /api/values/5 public string Get(int id) { return "value"; } // GET /api/values/5 [HttpGet] public string GetByFamily() { return "Family value"; } 

现在在global.asx

 routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapHttpRoute( name: "DefaultApi2", routeTemplate: "api/{controller}/{action}", defaults: new { id = RouteParameter.Optional } ); routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); 

您是否尝试切换到WebInvokeAttribute并将方法设置为“GET”?

我相信我有一个类似的问题,并切换到明确告诉哪些方法(GET / PUT / POST / DELETE)预计在大多数,如果不是全部,我的方法。

 public class SomeController : ApiController { [WebInvoke(UriTemplate = "{itemSource}/Items"), Method="GET"] public SomeValue GetItems(CustomParam parameter) { ... } [WebInvoke(UriTemplate = "{itemSource}/Items/{parent}", Method = "GET")] public SomeValue GetChildItems(CustomParam parameter, SomeObject parent) { ... } } 

WebGet 应该处理它,但我已经看到它有多个问题获取更less的多个获取相同的返回types。

[编辑:在WCF WebAPI的日落以及在MVC堆栈上迁移到ASP.Net WebAPI时,这些都不是有效的]

我试图使用Web Api 2属性路由来允许多个Get方法,并且我已经结合了以前答案中的有用build议,但是在Controller中,我只装饰了“特殊”方法(示例):

 [Route( "special/{id}" )] public IHttpActionResult GetSomethingSpecial( string id ) { 

…也不会在控制器的顶部放置[RoutePrefix]:

 [RoutePrefix("api/values")] public class ValuesController : ApiController 

我得到错误,指出找不到匹配提交的URI的路由。 一旦我有[路线]装饰的方法,以及[RoutePrefix]整体装饰控制器,它的工作。

上述例子都不符合我的个人需求。 下面是我最终做的。

  public class ContainsConstraint : IHttpRouteConstraint { public string[] array { get; set; } public bool match { get; set; } /// <summary> /// Check if param contains any of values listed in array. /// </summary> /// <param name="param">The param to test.</param> /// <param name="array">The items to compare against.</param> /// <param name="match">Whether we are matching or NOT matching.</param> public ContainsConstraint(string[] array, bool match) { this.array = array; this.match = match; } public bool Match(System.Net.Http.HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection) { if (values == null) // shouldn't ever hit this. return true; if (!values.ContainsKey(parameterName)) // make sure the parameter is there. return true; if (string.IsNullOrEmpty(values[parameterName].ToString())) // if the param key is empty in this case "action" add the method so it doesn't hit other methods like "GetStatus" values[parameterName] = request.Method.ToString(); bool contains = array.Contains(values[parameterName]); // this is an extension but all we are doing here is check if string array contains value you can create exten like this or use LINQ or whatever u like. if (contains == match) // checking if we want it to match or we don't want it to match return true; return false; } 

要在您的路线使用以上使用:

 config.Routes.MapHttpRoute("Default", "{controller}/{action}/{id}", new { action = RouteParameter.Optional, id = RouteParameter.Optional}, new { action = new ContainsConstraint( new string[] { "GET", "PUT", "DELETE", "POST" }, true) }); 

会发生什么是该方法中的假设约束types,以便此路由将只匹配默认的GET,POST,PUT和DELETE方法。 那里的“真”说我们要检查数组中项目的匹配。 如果它是假的,你会说排除那些在str中,然后可以使用这个默认方法之上的路线,如:

 config.Routes.MapHttpRoute("GetStatus", "{controller}/status/{status}", new { action = "GetStatus" }); 

在上面它本质上是寻找以下URL => http://www.domain.com/Account/Status/Active或类似的东西。

除了上述,我不确定我会太疯狂。 在一天结束时,应该是每个资源。 但是我确实看到了出于各种原因需要绘制友好的url。 Web Api的演变将会有某种规定,我感到非常确定。 如果时间我会build立一个更永久的解决scheme和后。

无法使上述任何路由解决scheme的工作 – 一些语法似乎已经改变,我仍然是新来的MVC – 在一个捏,虽然我把这个非常可怕的(和简单的)黑客这将使我现在注意,这取代了“public MyObject GetMyObjects(long id)”方法 – 我们将“id”的types改为一个string,并将返回types改为object。

 // GET api/MyObjects/5 // GET api/MyObjects/function public object GetMyObjects(string id) { id = (id ?? "").Trim(); // Check to see if "id" is equal to a "command" we support // and return alternate data. if (string.Equals(id, "count", StringComparison.OrdinalIgnoreCase)) { return db.MyObjects.LongCount(); } // We now return you back to your regularly scheduled // web service handler (more or less) var myObject = db.MyObjects.Find(long.Parse(id)); if (myObject == null) { throw new HttpResponseException ( Request.CreateResponse(HttpStatusCode.NotFound) ); } return myObject; } 

如果你在同一个文件中有多个Action,那么把相同的参数例如Id传递给所有的Action。 这是因为动作只能识别Id,所以不是给参数指定任何名称,而只是像这样声明Id。


 [httpget] [ActionName("firstAction")] firstAction(string Id) {..... ..... } [httpget] [ActionName("secondAction")] secondAction(Int Id) {..... ..... } //Now go to webroute.config file under App-start folder and add following routes.MapHttpRoute( name: "firstAction", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); routes.MapHttpRoute( name: "secondAction", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); 

修改WebApiConfig并在最后添加另一个Routes.MapHttpRoute,如下所示:

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

然后创build一个像这样的控制器:

 public class ServiceController : ApiController { [HttpGet] public string Get(int id) { return "object of id id"; } [HttpGet] public IQueryable<DropDownModel> DropDowEmpresa() { return db.Empresa.Where(x => x.Activo == true).Select(y => new DropDownModel { Id = y.Id, Value = y.Nombre, }); } [HttpGet] public IQueryable<DropDownModel> DropDowTipoContacto() { return db.TipoContacto.Select(y => new DropDownModel { Id = y.Id, Value = y.Nombre, }); } [HttpGet] public string FindProductsByName() { return "FindProductsByName"; } } 

这就是我解决它的方法。 我希望这会帮助别人。

使用更新的Web Api 2,拥有多个get方法变得更加容易。

如果传递给GET方法的参数对于属性路由系统来说是不同的,就像int s和Guid的情况一样,你可以在[Route...]属性中指定期望的types

例如 –

 [RoutePrefix("api/values")] public class ValuesController : ApiController { // GET api/values/7 [Route("{id:int}")] public string Get(int id) { return $"You entered an int - {id}"; } // GET api/values/AAC1FB7B-978B-4C39-A90D-271A031BFE5D [Route("{id:Guid}")] public string Get(Guid id) { return $"You entered a GUID - {id}"; } } 

有关此方法的更多详细信息,请参阅http://nodogmablog.bryanhogan.net/2017/02/web-api-2-controller-with-multiple-get-methods-part-2/

另一个select是给GET方法不同的路由。

  [RoutePrefix("api/values")] public class ValuesController : ApiController { public string Get() { return "simple get"; } [Route("geta")] public string GetA() { return "A"; } [Route("getb")] public string GetB() { return "B"; } } 

看到这里的更多细节 – http://nodogmablog.bryanhogan.net/2016/10/web-api-2-controller-with-multiple-get-methods/