C# 多个可选查询字符串参数RESTAPI GET

C# 多个可选查询字符串参数RESTAPI GET,c#,rest,asp.net-web-api,asp.net-web-api2,C#,Rest,Asp.net Web Api,Asp.net Web Api2,我正在使用WebAPI2实现restful服务。在对最佳实践进行了一些研究之后,每个人似乎都对如何做到以下几点有不同的看法。我有一个目标 public HttpResponseMessage Get(string crewId, string shiftDate, int offset = 1, int limit = 10) 此GET方法返回一个列表。有多种方法可以从该方法获取数据 仅限通过crewId 只能在换班时间到达 或 通过crewId和shiftDate获得 您(1)是否将crew

我正在使用WebAPI2实现restful服务。在对最佳实践进行了一些研究之后,每个人似乎都对如何做到以下几点有不同的看法。我有一个目标

public HttpResponseMessage Get(string crewId, string shiftDate, int offset = 1, int limit = 10)
此GET方法返回一个列表。有多种方法可以从该方法获取数据

  • 仅限通过crewId
  • 只能在换班时间到达
  • 通过crewId和shiftDate获得

    您(1)是否将crewId和shiftDate标记为可选

    public HttpResponseMessage Get(string crewId = null, string shiftDate = null, int offset = 1, int limit = 10)
    
    然后用一堆if语句来检查什么是填充的,什么是未填充的,以便能够执行操作

    if(crewId != null && shiftDate == null){
      // Get by crewId
    }else if(crewId == null && shiftDate != null){
      // Get By shiftDate
    }else if(crewId != null && shiftDate != null){
      // Get By crewId and shiftDate
    }
    
    对我来说,这样做看起来很疯狂,尤其是当你有很多参数时,你的代码中会有太多的“if”语句

    你(2)有不同的GET集合吗

    public HttpResponseMessage GetByCrewId(string crewId, int offset = 1, int limit = 10)
    public HttpResponseMessage GetByShiftDate(string shiftDate, int offset = 1, int limit = 10)
    public HttpResponseMessage GetByCrewIdShiftDate(string crewId, string shiftDate, int offset = 1, int limit = 10)
    
    然后将URI路由映射到该方法

  • ../api/GetByCrewId?crewId=1234
  • …/api/GetByShiftDate?shiftDate=1111-11-11
  • …/api/GetByCrewIdShiftDate?crewId=1234&shiftDate=1111-11-11
  • 选项2是restful吗

    还是有更好的选择(3)


    以上两个选项都能确保我使用最佳实践并遵循REST标准。我好像错过了什么,希望你能帮我找到正确的方向。

    我以前也做过类似的事情。由于您可以使用一个或另一个或两者,因此我将使用可选参数:

    public HttpResponseMessage Get(string crewId = null, string shiftDate = null, int offset = 1, int limit = 10)
    
    然后构造查询。例如,类似这样的内容:

    var query = "";
    if (!String.IsNullOrEmpty(crewId)) {
      query += $"crewId='{crewId}'";
    }
    if (!String.IsNullOrEmpty(shiftDate)) {
      if (query.Length > 0) query += " AND ";
      query += $"shiftDate='{shiftDate}'";
    }
    if (query.Length == 0) {
      //neither crewId or shiftDate were given
      //return some kind of error
    }
    
    您不希望选项(2)-为了实现RESTful,您希望URL中包含名词

    因此,您希望您的URL看起来像:

    /api/items/?crewId=1234&shiftDate=1111-11-11
    
    (根据'Crew'和'Shift'参数名称,我无法计算出您的项目是什么。什么项目有一个Crew和一个轮班日期??钓鱼旅行??如果是这样,url最好是/api/Fishing trips/?crewId=…&shiftDate=

    至于控制器,我会选择类似于:

    public HttpResponseMessage Get(string crewId = null, string shiftDate = null, int offset = 1, int limit = 10) {
    
        return dataSource.Where(x=> (x.CrewId == crewId || crewId == null)
                && (x.ShiftDate == shiftDate || shiftDate == null));
    }
    

    考虑到我将要自己实现它,我会说它应该是一个带有多个可选参数的
    GET
    方法操作

    为什么?因为您不应该担心REST API层中的查询逻辑。毕竟,您实际上是在创建一个带有多个参数的
    判别子句(即
    CrewId=1和ShiftDate=2016-01-01
    )。如果您不提供参数,则返回所有项目

    我将一直将参数传递给一个SQL存储过程,该存储过程指定了默认值,并将根据传递的参数返回结果

    请记住,在许多方面,REST方法直接映射到CRUD,因此请将您的API视为:

    查看它表明使用查询参数将表明它是可选的。如果您可以将单个值设为必需值,将其他值设为可选值,则可能有助于澄清URI

    /api/fishing-trips/crew/{crewid}?shiftdate=1111-11-11
    
    最后,如果您的项目都是可选的,那么使用“?”可能是最好的方法。有关参数类型的详细信息,请访问

    请注意,您的选择可能会影响您选择使用的任何队列,路径样式参数扩展可能最有意义。有关详细信息,请参阅

    最后,您可能希望创建这些作为搜索参数,然后,如果您发现您的用户经常请求相同的搜索,您可以将其打包到单个REST路径中

    比如说,

    /api/fishing-trips/search?crew=1234
    /api/fishing-trips/search?shiftDate=1111-11-11
    /api/fishing-trips/search?crew=1234&shiftDate=1111-11-11
    
    /api/fishing-trips/today
    /api/fishing-trips/today?crew=1234
    /api/fishing-trips/crew/1234/today
    
    您还可以提供简化和可选参数,例如

    /api/fishing-trips/search?crew=1234
    /api/fishing-trips/search?shiftDate=1111-11-11
    /api/fishing-trips/search?crew=1234&shiftDate=1111-11-11
    
    /api/fishing-trips/today
    /api/fishing-trips/today?crew=1234
    /api/fishing-trips/crew/1234/today
    

    根据我的研究,最后的这些例子是主观的,但是更多的信息可以在和上找到。

    谢谢你的回答@Anthony-我相信你仍然需要if语句,因为我甚至不想在数据库中查询shiftDate的crewId,如果其中一个为空的话-因为如果我按照你上面的回答做,它会看到e shiftDate或crewId为null并返回错误的数据集。但是GET的所有概念都与我目前很难同意的相同。控制器方法按照您的说法执行。以第一行为例:x.crewId==crewId | | crewId==null。如果crewId为null,则语句解析为true,记录将为null允许测试shiftDate。如果它也是null,那么shiftDate语句将解析为true,并返回记录。我看没关系-我的错误我快速浏览了linq语句我以为你有x.CrewId==null。你完全正确。只需浏览一下就很容易错过感谢Gabriel Luci的回答。我我现在拥有的是可选参数,但我很难理解,我必须对每个可能的结果使用if语句。如果我有n个参数,我将有n个可能性,这很疯狂,但可能是我无法同意自己的正确方式:)无论使用哪个标识符进行搜索,都可能存在一些常见的逻辑(例如,您总是查找“已启用”的记录或类似的内容)。因此,在多个控制器中复制该逻辑可能不是一个好主意。