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


136

我正在使用.Net MVC4 Web API来(希望)实现RESTful api。我需要向系统传递一些参数,并让它执行一些操作,然后返回对象列表作为结果。具体来说,我传递了两个日期并返回了两个日期之间的记录。我还跟踪返回的记录,以便后续调用不会在系统中得到重新处理。

我考虑了几种方法:

  1. 将参数序列化为一个JSON字符串,然后在API中将其分离。 http://forums.asp.net/t/1807316.aspx/1

  2. 在查询字符串中传递参数。
    将多个查询参数传递给静态API的最佳方法是什么?

  3. 定义路径中的参数:api / controller / date1 / date2

  4. 使用POST可以使我通过参数传递对象。

  5. 由于Web API(当前)支持ODATA,因此正在研究ODATA。我还没有做很多事情,所以我不太熟悉。

似乎正确的REST做法表明何时提取数据,应该使用GET。但是,GET也应该是无效的(不产生副作用),并且我想知道我的具体实现是否违反了该规定,因为我在API系统中标记了记录,因此产生了副作用。

这也使我想到了支持可变参数的问题。如果输入参数列表发生更改,那么如果必须经常为选择3重新定义您的路线,那将很麻烦。如果在运行时定义参数会发生什么...

无论如何,对于我的特定实现,哪种选择(如果有)似乎最好?

Answers:


10

该记录标记是什么意思?如果仅将其用于日志记录目的,我将使用GET并禁用所有缓存,因为您要记录此资源的每个查询。如果记录标记还有其他用途,则可以使用POST。用户应该知道,他的动作会影响系统,而POST方法是警告。


标记是指仅跟踪要处理和返回的记录,以便后续调用不会重复它们。就我而言,我只是在另一个表中插入一个以跟踪处理了哪些表。
sig606

现在,我确实将它实现为POST,主要是出于您所说的原因-发生了操作,并且消费者知道了它们。再加上它似乎很容易和最灵活的与RESP在通过不同的数据。
sig606

@ sig606:POST是适合我的方法,但是您的协议似乎并不安全。如果发生了什么事并且在客户端检索了记录但由于错误而未处理该怎么办?您将不再退还它们,并且客户端将丢失数据。
LukLed 2012年

现在,我的API仅在处理记录后才返回记录。因此,消费者将两个日期传递给API。处理和标记这两个日期之间的记录。然后,数据返回给调用方。我想如果在处理过程中或到达客户之前的处理后发生了什么问题,我有问题。
sig606

141

我认为最简单的方法就是简单地使用AttributeRouting

在控制器中很明显,为什么要在全局WebApiConfig文件中使用它?

例:

    [Route("api/YOURCONTROLLER/{paramOne}/{paramTwo}")]
    public string Get(int paramOne, int paramTwo)
    {
        return "The [Route] with multiple params worked";
    }

{}名称必须符合您的参数。

如此简单,现在您有一个单独的GET实例来处理此实例中的多个参数。


12
这很棒。大多数人建议在WebApiConfig文件中设置路由,但这确实更好。
rhyek 2015年

4
实际上,我们(大多数人)确实建议为您的配置设置一个集中的管理区域。对于Web API(Microsoft或其他),REST的集中式模式是关键。属性路由很可爱,但是它使一次性异常诱人。
大卫·贝兹

3
同意,我实际上需要更新我的答案。有一种使用GET处理多个参数的更好的方法。在我刚接触WebAPI时就发布了此内容,现在我不使用AttributeRouting(除非我只是不想创建一个新的Controller),而是将所有参数传递给QueryString,它们会自动映射。如果有机会,请更新,这样人们就不会使用这种较旧的方法
Mark Pieszak-Trilon.io 2015年

是否可以Route为命名参数(例如查询参数)设置?
Shimmy Weitzhandler 2015年

1
如果需要操作方法名称,则可以对其进行修改以适应这种情况。[Route(“ api / YOURCONTROLLER / Get / {paramOne} / {paramTwo}”)]公共字符串Get(int paramOne,int paramTwo){返回“某物”;}
Dash

49

只需在WebApiConfig条目中添加一条新路线即可。

例如,调用:

public IEnumerable<SampleObject> Get(int pageNumber, int pageSize) { ..

加:

config.Routes.MapHttpRoute(
    name: "GetPagedData",
    routeTemplate: "api/{controller}/{pageNumber}/{pageSize}"
);

然后将参数添加到HTTP调用中:

GET //<service address>/Api/Data/2/10 

10
这似乎是列出所有部分的唯一答案。我希望有人能更好地描述如何使用api/controller?start=date1&end=date2样式URI。
2014年

@Hotcks Andrew Veriga的答案与查询字符串参数很好地配合使用。本质上,您将查询字符串名称绑定到类属性,并将它们传递到您的方法中。您的方法将采用标记为[FromUri]属性的单个类参数,并将查询字符串参数作为其属性。
David Peterson

好东西。谢谢!
Hugo Nava Kopp

您好@HotLicks和GrahamWright您认为您可以回答这个问题吗?谢谢,stackoverflow.com

45

我只需要实现一个RESTfull api,即可在其中传递参数。我这样做是通过以与Mark第一个示例“ api / controller?start = date1&end = date2”所述的样式相同的方式在查询字符串中传递参数来实现的

在控制器中,我使用了C#中URL拆分的提示

// uri: /api/courses
public IEnumerable<Course> Get()
{
    NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
    var system = nvc["System"];
    // BL comes here
    return _courses;
}

就我而言,我是通过Ajax调用WebApi的,如下所示:

$.ajax({
        url: '/api/DbMetaData',
        type: 'GET',
        data: { system : 'My System',
                searchString: '123' },
        dataType: 'json',
        success: function (data) {
                  $.each(data, function (index, v) {
                  alert(index + ': ' + v.name);
                  });
         },
         statusCode: {
                  404: function () {
                       alert('Failed');
                       }
        }
   });

我希望这有帮助...


2
我猜您没有使用WebApi,因为ParameterBinding将自动将您的查询字符串映射到您的api方法参数...
emp

1
是的,更好的方法是使用[Route(“ api / DbMetaData / {system} / {searchString}”)]之类的属性,然后将其中的参数添加到Get(字符串系统,字符串searchString)中,然后使用“ ... api / DbMetaData / mysystem / mysearchstring“
Nigel Findlater

我在C#MVC WebApi中使用了他的示例,并且工作正常。例如+1
Si8

38

我在http://habrahabr.ru/post/164945/上找到了出色的解决方案

public class ResourceQuery
{
   public string Param1 { get; set; }
   public int OptionalParam2 { get; set; }
}

public class SampleResourceController : ApiController
{
    public SampleResourceModel Get([FromUri] ResourceQuery query)
    {
        // action
    }
}

5
线索是[FromUri]
tranceporter

2
尽管文章是俄语的,但@tranceporter是正确的。“ FromUri”看起来是从URL获取参数的好方法。另一篇可能有用的文章:asp.net/web-api/overview/formats-and-model-binding/…–
Greg

这是我已经进行了相当长一段时间的工作了,效果很好!我也推荐这种解决方案。
大卫·彼得森

如果您调用其他辅助方法(不是Get),是否仍可以使用[FromUri]?我似乎无法正常工作。
jocull

8

@LukLed清楚地说明了使用GETPOST方法。关于传递参数的方式,我建议采用第二种方法(我对ODATA也不太了解)。

1.将参数序列化为一个JSON字符串,然后在API中将其分开。http://forums.asp.net/t/1807316.aspx/1

这不是用户友好SEO友好

2.在查询字符串中传递参数。将多个查询参数传递给静态API的最佳方法是什么?

这是通常的首选方法。

3,定义路径中的参数:api / controller / date1 / date2

这绝对不是一个好方法。这让人感觉某人date2是它的子资源,但date1事实并非如此。无论是date1date2是查询参数,并配备在同一水平线上。

在简单的情况下,我建议使用这样的URI,

api/controller?start=date1&end=date2

但是我个人喜欢下面的URI模式,但是在这种情况下,我们必须编写一些自定义代码来映射参数。

api/controller/date1,date2

实际上,这些是我的原始解释。我认为LukLed使我的标签和URL链接大放异彩。
sig606

至于SEO,在这种情况下将不适用。该代码将是“服务器到服务器”的代码,因此我不在乎外界是否曾经发现它。实际上,我必须确保采取适当的安全措施以避免随机访问。我必须对系统的另一部分进行JSON序列化(似乎是试图发布obj较大列表的错误,因此我不得不序列化为字符串),因此在这种情况下不需要花很多时间。
sig606 2012年

1
我希望您已经有了答案,然后为什么要提问?
VJAI 2012年

2
马克,对不起,您的回复很晚。我曾尝试过几种解决方案,但不确定哪种方案最好,并一直坚持采用行业标准的方法,所以我在此处发表了文章。
sig606 2012年

1
@Mark下一个类似的东西:stackoverflow.com/questions/9681658/…
RredCat


3
 [Route("api/controller/{one}/{two}")]
    public string Get(int One, int Two)
    {
        return "both params of the root link({one},{two}) and Get function parameters (one, two)  should be same ";
    }

根链接的两个参数({one},{two})和Get函数参数(一个,两个)应该相同


2

我知道这确实很老,但是最近我想要同样的东西,这就是我发现的...

    public HttpResponseMessage Get([FromUri] string var, [FromUri] string test) {
        var retStr = new HttpResponseMessage(HttpStatusCode.OK);
        if (var.ToLower() == "getnew" && test.ToLower() == "test") {
            retStr.Content = new StringContent("Found Test", System.Text.Encoding.UTF8, "text/plain");
        } else {
            retStr.Content = new StringContent("Couldn't Find that test", System.Text.Encoding.UTF8, "text/plain");
        }

        return retStr;
    }

所以现在在您的地址/ URI / ...

http(s):// myURL / api / myController /?var = getnew&test = test

结果:“找到测试”


http(s):// myURL / api / myController /?var = getnew&test = anything

结果:“找不到该测试”


我个人喜欢C#中的这种样式,因为我可以更改原始方法的签名,并且可以完全重载我要完成的工作,而无需调整路由配置。希望它可以帮助其他习惯这种(可能过时)提出GET请求的方法。
里克·里格斯

1
我必须创建一个事件API,该事件API由使用这种方法的第三方日历应用程序使用。我很高兴找到这个答案!
clayRay


0
    public HttpResponseMessage Get(int id,string numb)
    {
        //this will differ according to your entity name
        using (MarketEntities entities = new MarketEntities())
        {
          var ent=  entities.Api_For_Test.FirstOrDefault(e => e.ID == id && e.IDNO.ToString()== numb);
            if (ent != null)
            {
                return Request.CreateResponse(HttpStatusCode.OK, ent);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Applicant with ID " + id.ToString() + " not found in the system");
            }
        }
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.