2012-02-29 348 views
120

在网页API我有一类结构相似的:处理ASP.NET Web API多个GET方法单控制器

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方法,但没有运气迄今为止解决这个问题。有关此问题的任何建议?

编辑:我忘了提,我现在想继续前进的ASP.NET Web API的代码具有不同的方法来路由。问题是,我如何使代码在ASP.NET Web API上工作?

+1

您是否仍然得到了{}父作为RouteParameter.Optional? – 2012-02-29 19:10:49

+0

是的,我做到了。也许我错误地使用了IActionValueBinder,因为对于像int id这样的类型(如在演示中),它确实工作正常。 – 2012-02-29 19:39:16

+0

对不起,我应该更清楚。我会认为将它作为可选项意味着它与项目路线以及子项目路线相匹配,这将解释您所看到的错误消息。 – 2012-02-29 19:48:00

回答

213

这是我发现支持额外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)}); 

我使用下面的测试类验证了此解决方案。我是能够成功地打每一种方法在我下面的控制器:

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操作不首先“获取'你可能想要为该方法添加一个HttpGet属性。

+4

这是一个很好的答案,并帮助我解决了另一个相关问题。谢谢!! – 2012-10-30 00:17:59

+1

+1我不知道正则表达式约束。 – nima 2013-05-29 08:11:38

+0

@ sky-dev。这对于PUT API是否适用? – shivakumar 2013-06-05 13:54:37

2

你试过切换到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 应该处理,但我已经看到了它有多重一些问题获得更多个相同的返回类型的获取。

[编辑:这一切都不是WCF的WebAPI的夕阳和迁移到ASP.Net的WebAPI的MVC堆栈上的有效]

+1

对不起,我忘记提到我将代码移到ASP.NET Web API,因为WCF Web API已经停止。我编辑了这篇文章。谢谢。 – 2012-02-29 16:25:40

10

你需要这样的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 } 
); 
+5

是的,这是真的,但它真的很高兴看到这些路线的例子。这将使这个答案对社区更有价值。 (你会得到我的+1 :) – 2012-10-24 02:32:47

+0

你可以在这里阅读一个例子 - http://stackoverflow.com/questions/11407267/multiple-httppost-method-in-mvc4-web-api-controller – 2012-11-27 11:11:08

+2

实际的解决方案会更好。 – 2012-12-30 20:27:40

3

我不知道如果u已经找到了答案,但我这样做,它的工作原理

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 } 
); 
47

转到此:

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://本地主机:8383/API /命令/ PostCreateUser”调用:

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

和张贴到“HTTP://本地主机:8383/API /命令/ PostMakeBooking “调用:

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

我在自托管的Web API服务应用程序尝试这样做,它的工作原理就像一个魅力:)

+4

感谢您的有用答案。我想补充一点,如果你使用Get,Post等开始你的方法名称,你的请求将映射到基于所使用的HTTP动词的方法。但是你也可以为你的方法命名,然后用'[HttpGet]',[HttpPost]等属性来修饰它们以将动词映射到方法。 – 2013-06-12 19:21:02

+0

感谢它适用于我.... – DineshChauhan 2015-03-12 07:30:32

+0

请看我的[问题](https://stackoverflow.com/questions/46680893/passing-multiple-parameters-to-web-api-get-method) – faisal1208 2017-10-11 06:23:16

0

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

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) }); 

会发生什么事是在方法约束那种假货,使这条航线将只匹配默认的GET,POST,PUT和DELETE方法。那里的“真”表示我们想要检查数组中项目的匹配。如果是假的,你会说,然后排除那些在strYou可以使用上面这个默认的方法途径,如:

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

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

除了上述我不确定我会太疯狂。在一天结束时,它应该是每个资源。但是我确实需要为各种原因映射友好的网址。随着Web Api的发展,我感到非常确定,会有某种规定。如果时间我会建立一个更持久的解决方案和后。

+0

您可以使用'new System.Web.Http.Routing.HttpMethodConstraint(HttpMethod.Get,HttpMethod.Post,HttpMethod.Put,HttpMethod.Delete)'。 – abatishchev 2014-01-25 06:09:51

0

无法使任何上述路由解决方案的工作 - 一些语法似乎已经改变,我仍然是新来的MVC - 在一个捏,虽然我把这真糟糕(和简单)的黑客现在我会得到 - 注意,这取代了“public MyObject GetMyObjects(long id)”方法 - 我们将“id”的类型更改为一个字符串,并将返回类型更改为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; 
} 
20

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

[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

+1

我需要在我的'WebApiApplication.Application_Start()'方法的末尾添加'config.MapHttpAttributeRoutes();'到我的'WebApiConfig.cs'和'GlobalConfiguration.Configuration.EnsureInitialized();'来获取路由属性上班。 – Ergwun 2017-02-23 05:10:54

0

如果您在同一个文件中有多个动作,则传递相同的参数,例如编号到所有行动。这是因为动作只能识别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 } 
); 
+0

Url如何看待浏览器中的每个功能? – Si8 2017-01-20 15:24:18

-1

修改WebApiConfig和在末尾添加另一Routes.MapHttpRoute这样的:

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

然后创建这样的控制器:

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"; 
     } 
} 

这是我如何解决它。我希望它能帮助别人。

0

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

如果传递给GET方法的参数是路由系统来区分他们的类型,与int S和Guid S中的情况下,你可以在[Route...]属性

例如指定所需类型的属性足够的不同 -

[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/

其他Ø ptions是给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/

2

我试图用网络API 2属性的路由,以允许多个Get方法,我已将以前的答案有益的建议,但在控制器我只装饰“特殊”方法(例如):

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

...而不同时也是在控制器的顶部放置一个[RoutePrefix]:

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

我收到错误,指出找不到与提交的URI匹配的路由。一旦我有[Route]装饰方法和[RoutePrefix]装饰整体控制器,它就起作用了。

1

在ASP.NET Core 2中。0您可以添加路线属性控制器:

[Route("api/[controller]/[action]")] 
public class SomeController : Controller 
{ 
    public SomeValue GetItems(CustomParam parameter) { ... } 

    public SomeValue GetChildItems(CustomParam parameter, SomeObject parent) { ... } 
} 
相关问题