在 ASP.NET Web API 中使用多个 Get 方法进行路由

Posted

技术标签:

【中文标题】在 ASP.NET Web API 中使用多个 Get 方法进行路由【英文标题】:Routing with multiple Get methods in ASP.NET Web API 【发布时间】:2012-09-28 08:11:57 【问题描述】:

我正在使用带有 ASP.NET MVC 的 Web Api,我对它很陌生。我已经在 asp.net 网站上浏览了一些演示,我正在尝试执行以下操作。

我有 4 个 get 方法,具有以下签名

public List<Customer> Get()

    // gets all customer


public List<Customer> GetCustomerByCurrentMonth()

    // gets some customer on some logic


public Customer GetCustomerById(string id)

    // gets a single customer using id


public Customer GetCustomerByUsername(string username)

    // gets a single customer using username

对于上述所有方法,我希望我的 web api 如下所示

列表获取() = api/customers/ 客户 GetCustomerById(字符串 ID) = api/customers/13 列出GetCustomerByCurrentMonth() = /customers/currentMonth 客户GetCustomerByUsername(字符串用户名)=/customers/customerByUsername/yasser

我尝试对路由进行更改,但由于我是新手,不太了解。

所以,请有人帮助我理解并指导我应该如何做到这一点。谢谢

【问题讨论】:

查看路由和操作过滤器 Api controller declaring more than one Get statement 的可能重复项 【参考方案1】:

从这里Routing in Asp.net Mvc 4 and Web Api

Darin Dimitrov 发布了一个非常适合我的答案。

上面写着……

你可以有几条路线:

public static class WebApiConfig

    public static void Register(HttpConfiguration config)
    
        config.Routes.MapHttpRoute(
            name: "ApiById",
            routeTemplate: "api/controller/id",
            defaults: new  id = RouteParameter.Optional ,
            constraints: new  id = @"^[0-9]+$" 
        );

        config.Routes.MapHttpRoute(
            name: "ApiByName",
            routeTemplate: "api/controller/action/name",
            defaults: null,
            constraints: new  name = @"^[a-z]+$" 
        );

        config.Routes.MapHttpRoute(
            name: "ApiByAction",
            routeTemplate: "api/controller/action",
            defaults: new  action = "Get" 
        );
    

【讨论】:

请看我的question 非常有帮助。我创建了多个 Get 方法,但没有将它们注册到 WebApiConfig 文件中。注册后就可以访问了。【参考方案2】:

首先,添加带有 action 的新路由:

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

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

然后使用ActionName属性映射:

[HttpGet]
public List<Customer> Get()

    //gets all customer


[ActionName("CurrentMonth")]
public List<Customer> GetCustomerByCurrentMonth()

    //gets some customer on some logic


[ActionName("customerById")]
public Customer GetCustomerById(string id)

    //gets a single customer using id


[ActionName("customerByUsername")]
public Customer GetCustomerByUsername(string username)

    //gets a single customer using username

【讨论】:

啊!这看起来很有希望,现在将尝试一下。 我试过了,除了api/customers//customers/customerByUsername/yasser 之外的所有工作我应该做些什么改变 我在问题上犯了一个错误,我已经更正了。请帮助 我仍然收到 http://localhost:61821/api/customers/ 的 500 内部服务器错误,非常感谢您在这方面帮助我,请再次帮助我 :) 这在纸上看起来不错,但实际上不起作用。您必须在这篇文章中执行类似于第二个答案的操作:***.com/questions/9569270/… 诀窍是在第一个路由中的 id 参数上添加一个 int 约束,并将默认操作设置为“Get”以及第二个路由上的 HttpGet 约束【参考方案3】:

您还将为设置路线指定行动路线

[HttpGet]
[Route("api/customers/")]
public List<Customer> Get()

   //gets all customer logic


[HttpGet]
[Route("api/customers/currentMonth")]
public List<Customer> GetCustomerByCurrentMonth()

     //gets some customer 


[HttpGet]
[Route("api/customers/id")]
public Customer GetCustomerById(string id)

  //gets a single customer by specified id

[HttpGet]
[Route("api/customers/customerByUsername/username")]
public Customer GetCustomerByUsername(string username)

    //gets customer by its username

【讨论】:

我认为这个答案简单明了,甚至与 .NET Core 兼容。然而,可以避免重复的路由前缀。见:***.com/questions/12775590/…【参考方案4】:

这个问题已经有很多很好的答案了。然而,现在 Route 配置有点“弃用”。较新版本的 MVC (.NET Core) 不支持它。所以最好习惯它:)

所以我同意所有使用属性样式路由的答案。但我一直注意到每个人都重复了路线的基础部分(api/...)。最好在 Controller 类之上应用 [RoutePrefix] 属性,不要一遍又一遍地重复相同的字符串。

[RoutePrefix("api/customers")]
public class MyController : Controller

 [HttpGet]
 public List<Customer> Get()
 
   //gets all customer logic
 

 [HttpGet]
 [Route("currentMonth")]
 public List<Customer> GetCustomerByCurrentMonth()
 
     //gets some customer 
 

 [HttpGet]
 [Route("id")]
 public Customer GetCustomerById(string id)
 
  //gets a single customer by specified id
 
 [HttpGet]
 [Route("customerByUsername/username")]
 public Customer GetCustomerByUsername(string username)
 
    //gets customer by its username
 

【讨论】:

【参考方案5】:

只有一条路线就够了

config.Routes.MapHttpRoute("DefaultApiWithAction", "controller/action");

并且需要在所有动作中指定属性HttpGetHttpPost

[HttpGet]
public IEnumerable<object> TestGet1()

    return new string[]  "value1", "value2" ;


[HttpGet]
public IEnumerable<object> TestGet2()

    return new string[]  "value3", "value4" ;

【讨论】:

【参考方案6】:

您可能不需要对路由进行任何更改。只需在您的 customersController.cs 文件中添加以下四个方法:

public ActionResult Index()



public ActionResult currentMonth()



public ActionResult customerById(int id)




public ActionResult customerByUsername(string userName)


将相关代码放入方法中。使用提供的默认路由,您应该根据给定 url 的操作和参数从控制器获得适当的操作结果。

修改你的默认路由为:

routes.MapRoute(
    "Default", // Route name
    "controller/action/id", // URL with parameters
    new  controller = "Api", action = "Index", id = UrlParameter.Optional  // Parameter defaults
);

【讨论】:

正确。控制器负责呈现给定的动作结果。要使这些方法像这样工作,您必须将其重命名为 customerController 或更改路由。如果要将控制器名称保留为 apicontroller,请更改路由并将控制器的默认值设置为“Api”而不是“Home”。 是的,我想保持名称不变,你能告诉我如何为此编写路由吗? 我已经编辑了路由,看看我如何将默认控制器从“Home”替换为“Api” 我不希望将索引作为控制器中的操作 索引用于您的默认网址“api/customers/”。您不必在 url 中放入 index,当未指定任何操作时,它会自动执行 Index 操作。在路线中看到,我们将“索引”作为默认操作。【参考方案7】:
  // this piece of code in the WebApiConfig.cs file or your custom bootstrap application class
  // define two types of routes 1. DefaultActionApi  and 2. DefaultApi as below

   config.Routes.MapHttpRoute("DefaultActionApi", "api/controller/action/id", new  id = RouteParameter.Optional );
   config.Routes.MapHttpRoute("DefaultApi", "api/controller/id", new  action = "Default", id = RouteParameter.Optional );

  // decorate the controller action method with [ActionName("Default")] which need to invoked with below url
  // http://localhost:XXXXX/api/Demo/ -- will invoke the Get method of Demo controller
  // http://localhost:XXXXX/api/Demo/GetAll -- will invoke the GetAll method of Demo controller
  // http://localhost:XXXXX/api/Demo/GetById -- will invoke the GetById method of Demo controller
  // http://localhost:57870/api/Demo/CustomGetDetails -- will invoke the CustomGetDetails method of Demo controller
  // http://localhost:57870/api/Demo/DemoGet -- will invoke the DemoGet method of Demo controller


 public class DemoController : ApiController
 
    // Mark the method with ActionName  attribute (defined in MapRoutes) 
    [ActionName("Default")]
    public HttpResponseMessage Get()
    
        return Request.CreateResponse(HttpStatusCode.OK, "Get Method");
    

    public HttpResponseMessage GetAll()
    
        return Request.CreateResponse(HttpStatusCode.OK, "GetAll Method");
    

    public HttpResponseMessage GetById()
    
        return Request.CreateResponse(HttpStatusCode.OK, "Getby Id Method");
    

    //Custom Method name
    [HttpGet]
    public HttpResponseMessage DemoGet()
    
        return Request.CreateResponse(HttpStatusCode.OK, "DemoGet Method");
    

    //Custom Method name
    [HttpGet]
    public HttpResponseMessage CustomGetDetails()
    
        return Request.CreateResponse(HttpStatusCode.OK, "CustomGetDetails Method");
    

【讨论】:

【参考方案8】:

我有两个 get 方法,参数相同或没有参数

[Route("api/ControllerName/FirstList")]
[HttpGet]
public IHttpActionResult FirstList()



[Route("api/ControllerName/SecondList")]
[HttpGet]
public IHttpActionResult SecondList()


只需在AppStart=&gt;WebApiConfig.cs中定义自定义路由=>在注册方法下

config.Routes.MapHttpRoute(
       name: "GetFirstList",
       routeTemplate: "api/Controllername/FirstList"          
       );
config.Routes.MapHttpRoute(
       name: "GetSecondList",
       routeTemplate: "api/Controllername/SecondList"          
       );

【讨论】:

【参考方案9】:

在阅读了很多答案后,我终于想通了。

首先,我在 WebApiConfig.cs 中添加了 3 个不同的路由

public static void Register(HttpConfiguration config)

    // Web API configuration and services

    // Web API routes
    config.MapHttpAttributeRoutes();

    config.Routes.MapHttpRoute(
        name: "ApiById",
        routeTemplate: "api/controller/id",
        defaults: new  id = RouteParameter.Optional ,
        constraints: new  id = @"^[0-9]+$" 
    );

    config.Routes.MapHttpRoute(
        name: "ApiByName",
        routeTemplate: "api/controller/action/name",
        defaults: null,
        constraints: new  name = @"^[a-z]+$" 
    );

    config.Routes.MapHttpRoute(
        name: "ApiByAction",
        routeTemplate: "api/controller/action",
        defaults: new  action = "Get" 
    );

然后,从控制器函数中删除 ActionName、Route 等。所以基本上这是我的控制器;

// GET: api/Countries/5
[ResponseType(typeof(Countries))]
//[ActionName("CountryById")]
public async Task<IHttpActionResult> GetCountries(int id)

    Countries countries = await db.Countries.FindAsync(id);
    if (countries == null)
    
        return NotFound();
    

    return Ok(countries);


// GET: api/Countries/tur
//[ResponseType(typeof(Countries))]
////[Route("api/CountriesByName/anyString")]
////[ActionName("CountriesByName")]
//[HttpGet]
[ResponseType(typeof(Countries))]
//[ActionName("CountryByName")]
public async Task<IHttpActionResult> GetCountriesByName(string name)

    var countries = await db.Countries
            .Where(s=>s.Country.ToString().StartsWith(name))
            .ToListAsync();

    if (countries == null)
    
        return NotFound();
    

    return Ok(countries);

现在我可以使用以下 url 示例(带有名称和 id)运行;

http://localhost:49787/api/Countries/GetCountriesByName/France

http://localhost:49787/api/Countries/1

【讨论】:

【参考方案10】:
using Routing.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace Routing.Controllers

    public class StudentsController : ApiController
    
        static List<Students> Lststudents =
              new List<Students>()  new Students  id=1, name="kim" ,
           new Students  id=2, name="aman" ,
            new Students  id=3, name="shikha" ,
            new Students  id=4, name="ria"  ;

        [HttpGet]
        public IEnumerable<Students> getlist()
        
            return Lststudents;
        

        [HttpGet]
        public Students getcurrentstudent(int id)
        
            return Lststudents.FirstOrDefault(e => e.id == id);
        
        [HttpGet]
        [Route("api/Students/id/course")]
        public IEnumerable<string> getcurrentCourse(int id)
        
            if (id == 1)
                return new List<string>()  "emgili", "hindi", "pun" ;
            if (id == 2)
                return new List<string>()  "math" ;
            if (id == 3)
                return new List<string>()  "c#", "webapi" ;
            else return new List<string>()  ;
        

        [HttpGet]
        [Route("api/students/id/name")]
        public IEnumerable<Students> getlist(int id, string name)
         return Lststudents.Where(e => e.id == id && e.name == name).ToList(); 

        [HttpGet]
        public IEnumerable<string> getlistcourse(int id, string name)
        
            if (id == 1 && name == "kim")
                return new List<string>()  "emgili", "hindi", "pun" ;
            if (id == 2 && name == "aman")
                return new List<string>()  "math" ;
            else return new List<string>()  "no data" ;
        
    

【讨论】:

以上是关于在 ASP.NET Web API 中使用多个 Get 方法进行路由的主要内容,如果未能解决你的问题,请参考以下文章

支持多个版本的ASP.NET Core Web API

从 ASP.NET MVC Web API 中的多个表单数据键接收文件

(Asp.Net MVC / Web-Api)中具有相同身份验证系统的多个项目

我应该如何将多个参数传递给 ASP.Net Web API GET?

具有相同路由前缀 ASP.NET Web Api 的多个控制器类型

通过 ASP.NET Core Web API 使用存储过程从 SQL Server 返回多个行集