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

Posted

技术标签:

【中文标题】如何使用 ASP.NET Core 从查询字符串中读取值?【英文标题】:How to read values from the querystring with ASP.NET Core? 【发布时间】:2017-05-25 10:43:45 【问题描述】:

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

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

我已经发现在控制器内部Get 操作访问HttpContext.Request.Query 会返回一个IQueryCollection

问题是我不知道如何使用它来检索值。事实上,我认为这样做的方法是使用,例如

string page = HttpContext.Request.Query["page"]

问题是HttpContext.Request.Query["page"] 不返回字符串,而是StringValues

无论如何,如何使用IQueryCollection 来实际读取查询字符串值?

【问题讨论】:

【参考方案1】:

如果您想在 asp.net 核心视图中访问 QueryString,您可以这样做:

@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor

@if (Context.Request.Query.Keys.Any())

    <button>--ClearFilters--</button>

【讨论】:

【参考方案2】:
    Startup.cs添加此服务 services.AddSingleton&lt;IHttpContextAccessor, HttpContextAccessor&gt;(); 您的视图添加注入 @inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor 获得您的价值

代码

@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
@
    var id = HttpContextAccessor.HttpContext.Request.RouteValues["id"];

    if (id != null)
    
        // parameter exist in your URL 
    

【讨论】:

【参考方案3】:

ASP.NET Core 将自动按名称绑定 form valuesroute valuesquery strings。这意味着您可以简单地这样做:

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

MVC 将尝试按名称将请求数据绑定到操作参数...下面是数据源列表,按模型绑定查看它们的顺序排列

    Form values:这些是使用 POST 方法进入 HTTP 请求的表单值。 (包括 jQuery POST 请求)。

    Route values: Routing 提供的路由值集合

    Query strings:URI 的查询字符串部分。

来源:Model Binding in ASP.NET Core


仅供参考,您还可以结合自动和显式方法:

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

【讨论】:

虽然不是操作员问题的答案,但对于出于类似原因来到这里的人来说,这是一个非常有用的答案。【参考方案4】:

也许有帮助。 获取视图中的查询字符串参数

查看:

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

Startup.cs 配置服务:

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

【讨论】:

【参考方案5】:

一些 cmets 也提到了这一点,但 asp net core 会为您完成所有这些工作。

如果您有一个与名称匹配的查询字符串,它将在控制器中可用。

https://myapi/some-endpoint/123?someQueryString=YayThisWorks

[HttpPost]
[Route("some-endpoint/someValue")]
public IActionResult SomeEndpointMethod(int someValue, string someQueryString)
    
        Debug.WriteLine(someValue);
        Debug.WriteLine(someQueryString);
        return Ok();
    

输出:

123

YayThisWorks

【讨论】:

【参考方案6】:

我对这个问题有更好的解决方案,

request 是抽象类 ControllerBase 的成员 GetSearchParams() 是在 bellow helper 中创建的扩展方法 类。

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 在什么命名空间中找到?【参考方案7】:

如果您想在我们的视图中访问查询字符串,请在 .net 核心中使用它,就像

@Context.Request.Query["yourKey"]

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

@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
@if (HttpContextAccessor.HttpContext.Request.Query.Keys.Contains("yourKey"))

      <text>do something </text>

也适用于 cookie

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

【讨论】:

不需要所有的代码。只需使用 @Context.Request.Query["yourKey"] 是的@ShadiNamrouti,您在 \@Context 可用的视图中是正确的,我们可以像 \@Context.Request.Query["yourKey"] 一样使用它,但如果我们在控制器中,我们需要注入HttpContextAccessor.HttpContext.【参考方案8】:

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

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。会不会是 example.com/somequery/… 之类的东西? @Christian 如果您不更改任何约定,它将是 example.com/[controller]/[action]/someid:int?someparameter=1&someparameter2=2【参考方案9】:

StringValues 是一个array of strings。您可以通过提供索引来获取字符串值,例如HttpContext.Request.Query["page"][0].

【讨论】:

谢谢;这是唯一真正回答了这个问题的回答。 (在我的情况下,我不能使用绑定,因为我有一个更复杂的逻辑,比如“首先尝试查询字符串,如果缺少尝试会话等等”。)【参考方案10】:

这是我使用过的代码示例(带有 .NET Core 视图):

@
    Microsoft.Extensions.Primitives.StringValues queryVal;

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

【讨论】:

赞成包含完整的对象名称(或正确的 using 语句)。当人们只输入没有完全限定或至少使用语句的对象名时,我会发疯。谢谢。【参考方案11】:

您可以使用[FromQuery] 将特定模型绑定到查询字符串:

https://docs.microsoft.com/en-us/aspnet/core/mvc/models/model-binding

例如

[HttpGet()]
public IActionResult Get([FromQuery(Name = "page")] string page)
...

【讨论】:

我认为[FromQuery]属性也可以省略,因为.net绑定默认会检查所有表单输入和url查询字符串参数,除非你有一些理由限制它的来源。跨度> (Name = "page") 是不必要的 - 如果名称相同,它将绑定到变量 如果查询字符串参数名称是结构化的,这一点很重要。例如'object.propname'【参考方案12】:

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

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

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

【讨论】:

要添加到这个答案,如果你调用 StringValues.ToString() 如果你需要的话,你可以将它直接转换为字符串。 未来读者:完全限定名称“Microsoft.AspNetCore.Http.IQueryCollection queryString = this.Request.Query;”我的是“Assembly Microsoft.AspNetCore.Http.Features, Version=3.1.0.0”和“Microsoft.Extensions.Primitives.StringValues”(我的是“Assembly Microsoft.Extensions.Primitives, Version=3.1.2.0”) 【参考方案13】:

您可以在 IQueryCollection 上使用 ToString 方法,如果指定了单个 page 参数,它将返回所需的值:

string page = HttpContext.Request.Query["page"].ToString();

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

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

【讨论】:

ToString 不是必需的。如果您将查询值分配给字符串,编译器将隐式转换它.. 添加 ToString() 甚至很危险。如果 URL 没有查询字符串 ID,则返回值为 null(docs.microsoft.com/en-us/dotnet/api/…) 并导致 NullReference 异常。

以上是关于如何使用 ASP.NET Core 从查询字符串中读取值?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Asp.net Core 中的查询字符串验证 Azure AD B2C 令牌?

如何让 ASP.NET Core 支持绑定查询字符串中的数组

Linq 查询在 ASP.NET-Core 3.0 及更高版本中对数字等字符串进行排序

如何让 ASP.NET Core 支持绑定查询字符串中的数组

如何使用 ASP.NET Core 将查询字符串参数转换为看起来像目录部分?

ASP.NET Core Web API - 如何处理 URL 查询字符串中的“null”与“undefined”?