如何在ASP.NET Core中从查询字符串读取值?

277

我正在使用ASP.NET Core MVC构建一个RESTful API,并希望使用查询字符串参数来指定返回集合资源的过滤和分页。

在这种情况下,我需要读取传递给查询字符串的值以进行过滤和选择要返回的结果。

我已经发现,在控制器的Get操作中访问HttpContext.Request.Query将返回一个IQueryCollection

问题是我不知道如何使用它来检索值。事实上,我认为可以使用以下方式

string page = HttpContext.Request.Query["page"]
问题在于HttpContext.Request.Query["page"]返回的不是字符串,而是一个StringValues

那么,如何使用IQueryCollection来读取查询字符串的值呢?

15个回答

248

13
我认为 [FromQuery] 特性也可以省略,因为 .NET 绑定默认会检查所有表单输入和 URL 查询字符串参数,除非您有某些原因限制其来源。 - S.Serpooshan
41
如果变量名和 (Name = "page") 相同,它是无必要的 - 它会绑定到该变量。 - a3uge
3
如果查询字符串参数名称是结构化的,这一点非常重要。例如,“object.propname”。 - Jose Capistrano

167
你可以在 IQueryCollection 上使用 ToString 方法,如果指定了一个单独的 page 参数,它将返回所需的值:
string page = HttpContext.Request.Query["page"].ToString();

如果有多个值,例如?page=1&page=2,则ToString调用的结果将是1,2

但是,正如@mike-g在他的答案中建议的那样,最好使用模型绑定而不是直接访问HttpContext.Request.Query对象。


15
ToString不是必需的。如果将查询值分配给字符串,编译器会隐式转换它。 - Stefan Steiger
7
添加ToString()甚至是有风险的。如果URL没有查询字符串ID,返回值将为null(https://learn.microsoft.com/en-us/dotnet/api/system.web.httprequest.querystring?view=netframework-4.8#examples),并导致NullReference异常。 - Michael Freidgeim
2
@MichaelFreidgeim 不是这样的,也不会是这样的,StringValues 是一个结构体,它不能为 null,此外你提供的链接指向了 NET Framework 文章。 - Alex from Jitbit
2
@AlexfromJitbit,你说得对,在Asp.Net Core中,如果键不存在,它会返回StringValues.Empty。https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.iquerycollection.item?view=aspnetcore-7.0#microsoft-aspnetcore-http-iquerycollection-item(system-string) - undefined
1
@AlexfromJitbit,你是对的,在Asp.Net Core中,如果键不存在,则返回StringValues.Empty。https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.iquerycollection.item?view=aspnetcore-7.0#microsoft-aspnetcore-http-iquerycollection-item(system-string) - Michael Freidgeim
@Darin,您能否检查一下这个帖子。https://stackoverflow.com/questions/75846918/how-to-read-the-querystring-value-not-working - Prageeth Liyanage

73

ASP.NET Core会根据名称自动绑定表单值路由值查询字符串。这意味着您只需执行以下操作:

[HttpGet()]
public IActionResult Get(int page)
{ ... }

MVC将尝试按名称将请求数据绑定到操作参数上...以下是按模型绑定查找它们的顺序列表

  1. 表单值: 这些是使用POST方法在HTTP请求中发送的表单值。(包括jQuery POST请求)。

  2. 路由值: 路由提供的一组路由值

  3. 查询字符串: URI的查询字符串部分。

来源:ASP.NET Core中的模型绑定


顺便说一句,您也可以将自动和显式方法结合使用:

[HttpGet()]
public IActionResult Get(int page
     , [FromQuery(Name = "page-size")] int pageSize)
{ ... }

4
虽然这并不是回答提问者问题的答案,但对于那些因为类似原因来到这里的人来说,这是非常有用的答案。 - Mmm

45

这是我使用过的一段代码示例(使用了.NET Core视图):

@{
    Microsoft.Extensions.Primitives.StringValues queryVal;

    if (Context.Request.Query.TryGetValue("yourKey", out queryVal) &&
        queryVal.FirstOrDefault() == "yourValue")
    {
    }
}

19
请点赞以包含完整的对象名称(或正确的使用语句)。当人们只放置对象名称而没有完全限定或至少一个使用语句时,会让我抓狂。谢谢。 - granadaCoder

37

您可以像这样创建一个对象:

public class SomeQuery
{
    public string SomeParameter { get; set; }
    public int? SomeParameter2 { get; set; }
}

然后在控制器中只需要做出类似这样的操作:

[HttpGet]
public IActionResult FindSomething([FromQuery] SomeQuery query)
{
    // Your implementation goes here..
}

更好的是,您可以从以下内容中创建API模型:

[HttpGet]
public IActionResult GetSomething([FromRoute] int someId, [FromQuery] SomeQuery query)

收件人:

[HttpGet]
public IActionResult GetSomething(ApiModel model)

public class ApiModel
{
    [FromRoute]
    public int SomeId { get; set; }
    [FromQuery]
    public string SomeParameter { get; set; }
    [FromQuery]
    public int? SomeParameter2 { get; set; }
}

这适用于哪个URL?我是新手,无法“反向工程”到URL。它会像http://example.com/somequery/findquery?someparameter1=1&someparameter2=2这样吗? - Christian
1
@Christian 如果您不更改任何约定,那么它将是example.com/[controller]/[action]/{someid:int}?someparameter=1&someparameter2=2。 - LxL

25

StringValues是一个字符串数组。你可以通过提供索引来获取你的字符串值,例如:HttpContext.Request.Query["page"][0]


3
谢谢,这是唯一一个真正回答了问题的答复。(在我的情况下,我不能使用binding,因为我有更复杂的逻辑,比如“首先尝试查询字符串,如果缺少则尝试会话等等”。) - Marcel Popescu
找了很多地方后终于找到完美的答案。 - Hardik Masalawala

12

IQueryCollection有一个TryGetValue()方法,可以返回给定键的值。因此,如果您有一个名为someInt的查询参数,可以像这样使用它:

var queryString = httpContext.Request.Query;
StringValues someInt;
queryString.TryGetValue("someInt", out someInt);
var daRealInt = int.Parse(someInt);

请注意,除非您具有相同名称的多个参数,否则StringValues类型不是问题。


补充一下,如果你调用StringValues.ToString(),你可以直接将其转换为字符串,如果这是你所需要的。 - eltiare
未来的读者们:完全限定名称为“Microsoft.AspNetCore.Http.IQueryCollection queryString = this.Request.Query;”我的是在“程序集 Microsoft.AspNetCore.Http.Features,版本=3.1.0.0”中,而“Microsoft.Extensions.Primitives.StringValues”(我的是在“程序集 Microsoft.Extensions.Primitives,版本=3.1.2.0”中)。 - granadaCoder

11
在 .NET Core 中,如果您想在视图中访问查询字符串,请使用以下方式:
@Context.Request.Query["yourKey"]

如果我们所在的位置没有@Context可用,我们可以像这样注入它

@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
@if (HttpContextAccessor.HttpContext.Request.Query.Keys.Contains("yourKey"))
{
      <text>do something </text>
}

同样适用于cookies

HttpContextAccessor.HttpContext.Request.Cookies["DeniedActions"]

2
不需要那么多代码,只需使用@Context.Request.Query["yourKey"]。 - Shadi Alnamrouti
是的,@ShadiNamrouti,在@Context可用的情况下,我们可以像这样使用它:@Context.Request.Query["yourKey"],但如果我们在控制器中,我们需要注入HttpContextAccessor.HttpContext。 - M.Ali El-Sayed

8

也许这会有所帮助。 在视图中获取查询字符串参数。

视图:

@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
@{ Context.Request.Query["uid"]}

Startup.cs的ConfigureServices方法:

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

3

我有一个更好的解决方案:

  • 请求是抽象类ControllerBase的成员
  • GetSearchParams()是下面辅助类中创建的扩展方法。

var searchparams = await Request.GetSearchParams();

我创建了一个静态类,其中包含几个扩展方法。

public static class HttpRequestExtension
{
  public static async Task<SearchParams> GetSearchParams(this HttpRequest request)
        {
            var parameters = await request.TupledParameters();

            try
            {
                for (var i = 0; i < parameters.Count; i++)
                {
                    if (parameters[i].Item1 == "_count" && parameters[i].Item2 == "0")
                    {
                        parameters[i] = new Tuple<string, string>("_summary", "count");
                    }
                }
                var searchCommand = SearchParams.FromUriParamList(parameters);
                return searchCommand;
            }
            catch (FormatException formatException)
            {
                throw new FhirException(formatException.Message, OperationOutcome.IssueType.Invalid, OperationOutcome.IssueSeverity.Fatal, HttpStatusCode.BadRequest);
            }
        }



public static async Task<List<Tuple<string, string>>> TupledParameters(this HttpRequest request)
{
        var list = new List<Tuple<string, string>>();


        var query = request.Query;
        foreach (var pair in query)
        {
            list.Add(new Tuple<string, string>(pair.Key, pair.Value));
        }

        if (!request.HasFormContentType)
        {
            return list;
        }
        var getContent = await request.ReadFormAsync();

        if (getContent == null)
        {
            return list;
        }
        foreach (var key in getContent.Keys)
        {
            if (!getContent.TryGetValue(key, out StringValues values))
            {
                continue;
            }
            foreach (var value in values)
            {
                list.Add(new Tuple<string, string>(key, value));
            }
        }
        return list;
    }
}

通过这种方式,您可以轻松访问所有搜索参数。我希望这能帮助到很多开发人员 :)


我是否遗漏了什么 - FhirException 定义在哪里,Task<SearchParams> 在哪个命名空间中找到? - Doug Thompson - DouggyFresh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接