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

pau*_*s_l 156 c# asp.net-web-api

在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) { ... }
}
Run Code Online (Sandbox Code Playgroud)

由于我们可以映射单个方法,因此在正确的位置获得正确的请求非常简单.对于只有一个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
Run Code Online (Sandbox Code Playgroud)

我试图通过重写ExecuteAsync方法来解决这个问题ApiController但到目前为止没有运气.关于这个问题的任何建议?

编辑:我忘了提到现在我试图在ASP.NET Web API上移动此代码,它具有不同的路由方法.问题是,如何使代码在ASP.NET Web API上运行?

sky*_*dev 241

这是我发现支持额外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)});
Run Code Online (Sandbox Code Playgroud)

我用下面的测试类验证了这个解决方案.我能够成功点击下面控制器中的每个方法:

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)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

我确认它支持以下请求:

GET /Test
GET /Test/1
GET /Test/GetAll
POST /Test
PUT /Test/1
DELETE /Test/1
Run Code Online (Sandbox Code Playgroud)

注意如果您的额外GET操作不以"Get"开头,您可能希望向该方法添加HttpGet属性.

  • 这是一个很好的答案,它帮助了我很多另一个相关的问题.谢谢!! (4认同)
  • 试过这个 - 似乎不起作用.路由都是随机映射到GetBlah(long id)方法.:( (4认同)
  • 如何添加一个方法 - Get(int id,string name)?...它失败 (4认同)

小智 57

从这里开始:

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

对此:

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

因此,您现在可以指定要将HTTP请求发送到的操作(方法).

发布到"http:// localhost:8383/api/Command/PostCreateUser"调用:

public bool PostCreateUser(CreateUserCommand command)
{
    //* ... *//
    return true;
}
Run Code Online (Sandbox Code Playgroud)

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

public bool PostMakeBooking(MakeBookingCommand command)
{
    //* ... *//
    return true;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 谢谢你的回答.我想补充一点,如果你用Get,Post等开始你的方法名,你的请求将根据所使用的HTTP动词映射到那些方法.但你也可以将你的方法命名为任何东西,然后使用`[HttpGet]`,`[HttpPost]`等属性来装饰它们,以将动词映射到方法. (8认同)

Kal*_*ade 29

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

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

}
Run Code Online (Sandbox Code Playgroud)

您还需要在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 }
);
Run Code Online (Sandbox Code Playgroud)

一些好的链接 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

  • 我还需要在我的WebApiConfig.cs中添加config.MapHttpAttributeRoutes();和在WebApiApplication.Application_Start()方法末尾的GlobalConfiguration.Configuration.EnsureInitialized();中添加路由属性。工作。 (2认同)

Ale*_*ler 11

您需要在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 }
);
Run Code Online (Sandbox Code Playgroud)

  • 是的,这是真的,但实际上看到这些路线的例子会很好.这会使这个答案对社区更有价值.(你从我那里得到+1 :) (5认同)
  • 一个实际的解决方案会更好. (2认同)

mas*_*lek 7

在 ASP.NET Core 2.0 中,您可以将Route属性添加到控制器:

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

    public SomeValue GetChildItems(CustomParam parameter, SomeObject parent) { ... }
}
Run Code Online (Sandbox Code Playgroud)


小智 7

在 VS 2019 中,这很容易实现:

[Route("api/[controller]/[action]")] //above the controller class
Run Code Online (Sandbox Code Playgroud)

在代码中:

[HttpGet]
[ActionName("GetSample1")]
public Ilist<Sample1> GetSample1()
{
    return getSample1();
}
[HttpGet]
[ActionName("GetSample2")]
public Ilist<Sample2> GetSample2()
{
    return getSample2();
}
[HttpGet]
[ActionName("GetSample3")]
public Ilist<Sample3> GetSample3()
{
    return getSample3();
}
[HttpGet]
[ActionName("GetSample4")]
public Ilist<Sample4> GetSample4()
{
    return getSample4();
}
Run Code Online (Sandbox Code Playgroud)

您可以像上面提到的那样有多个获取。


Bry*_*yan 6

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

如果传递给GET方法的参数足够不同,以使属性路由系统能够像ints和Guids 一样区分其类型,则可以在[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}";
    }
} 
Run Code Online (Sandbox Code Playgroud)

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

另一种选择是为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";
        }
   }
Run Code Online (Sandbox Code Playgroud)

详情请参阅这里-http://nodogmablog.bryanhogan.net/2016/10/web-api-2-controller-with-multiple-get-methods/


Art*_*nig 6

懒惰/匆忙的替代方案(Dotnet Core 2.2):

[HttpGet("method1-{item}")]
public string Method1(var item) { 
return "hello" + item;}

[HttpGet("method2-{item}")]
public string Method2(var item) { 
return "world" + item;}
Run Code Online (Sandbox Code Playgroud)

打电话给他们:

本地主机:5000/api/控制器名称/method1-42

“你好42”

本地主机:5000/api/控制器名称/method2-99

“世界99”


小智 6

默认情况下 [Route("api/[controller]") 将由 .Net Core/Asp.Net Web API 生成。您需要修改一点,只需添加 [Action],如 [Route("api/[controller]/[行动]”)]。我已经提到了一个虚拟解决方案:

// Default generated controller
//
[Route("api/[controller]")
public class myApiController : Controller
{
    [HttpGet]
    public string GetInfo()
    {
        return "Information";
    }
}

//
//A little change would do the magic
//

[Route("api/[controller]/[action]")]
public class ServicesController : Controller
{
    [HttpGet]
    [ActionName("Get01")]
    public string Get01()
    {
        return "GET 1";
    }

    [HttpGet]
    [ActionName("Get02")]
    public string Get02()
    {
        return "Get 2";
    }
    
    [HttpPost]
    [ActionName("Post01")]
    public HttpResponseMessage Post01(MyCustomModel01 model)
    {
        if (!ModelState.IsValid)
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        
        //.. DO Something ..
        return Request.CreateResonse(HttpStatusCode.OK, "Optional Message");
    }
    
    [HttpPost]
    [ActionName("Post02")]
    public HttpResponseMessage Post02(MyCustomModel02 model)
    {
        if (!ModelState.IsValid)
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        
        //.. DO Something ..
        return Request.CreateResonse(HttpStatusCode.OK, "Optional Message");
    }


}
Run Code Online (Sandbox Code Playgroud)