Làm thế nào để đọc các giá trị từ chuỗi truy vấn với ASP.NET Core?


135

Tôi đang xây dựng một API RESTful bằng ASP.NET Core MVC và tôi muốn sử dụng các tham số chuỗi truy vấn để chỉ định lọc và phân trang trên tài nguyên trả về một bộ sưu tập.

Trong trường hợp đó, tôi cần đọc các giá trị được truyền trong chuỗi truy vấn để lọc và chọn kết quả để trả về.

Tôi đã phát hiện ra rằng bên trong bộ điều khiển Gethành động truy cập HttpContext.Request.Querytrả về một IQueryCollection.

Vấn đề là tôi không biết làm thế nào nó được sử dụng để lấy các giá trị. Trong thực tế, tôi nghĩ rằng cách để làm là bằng cách sử dụng, ví dụ

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

Vấn đề là HttpContext.Request.Query["page"]không trả về một chuỗi, nhưng a StringValues.

Dù sao, làm thế nào để người ta sử dụng IQueryCollectionđể thực sự đọc các giá trị chuỗi truy vấn?


1
Tôi đã viết một bài cho cùng một thứ mà bạn có thể tìm thấy ở đây: neelbhatt40.wordpress.com/2017/07/06/ mẹo
Neel

Câu trả lời:


134

Bạn có thể sử dụng [FromQuery]để liên kết một mô hình cụ thể với chuỗi truy vấn:

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

ví dụ

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

5
Tôi nghĩ rằng [FromQuery]attrib cũng có thể được sử dụng vì liên kết .net sẽ kiểm tra tất cả các đầu vào biểu mẫu và tham số chuỗi truy vấn url theo mặc định, ngoại trừ việc bạn có một số lý do để giới hạn nguồn của nó.
S.Serpoo Sơn

12
(Tên = "trang") là không cần thiết - nó sẽ liên kết với biến nếu được đặt tên giống nhau
a3uge

Điều này rất quan trọng nếu tên tham số chuỗi truy vấn được cấu trúc. Ví dụ: 'object.propname'
Jose Capistrano

96

Bạn có thể sử dụng phương thức ToString IQueryCollectionsẽ trả về giá trị mong muốn nếu một pagetham số duy nhất được chỉ định:

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

nếu có nhiều giá trị như thế ?page=1&page=2thì kết quả của lệnh gọi ToString sẽ là1,2

Nhưng như @ mike-g đã đề xuất trong câu trả lời của anh ấy, bạn nên sử dụng ràng buộc mô hình và không truy cập trực tiếp vào HttpContext.Request.Queryđối tượng.


6
ToString là không cần thiết. Trình biên dịch sẽ bỏ mặc nó, nếu bạn gán giá trị truy vấn cho một chuỗi ..
Stefan Steiger

26

ASP.NET Core sẽ tự động ràng buộc form values, route valuesquery stringstheo tên. Điều này có nghĩa là bạn có thể chỉ cần làm điều này:

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

MVC sẽ cố gắng liên kết dữ liệu yêu cầu với các tham số hành động theo tên ... bên dưới là danh sách các nguồn dữ liệu theo thứ tự mà mô hình ràng buộc nhìn qua chúng

  1. Form values: Đây là các giá trị biểu mẫu đi trong yêu cầu HTTP bằng phương thức POST. (bao gồm các yêu cầu POST của jQuery).

  2. Route values: Tập hợp các giá trị tuyến được cung cấp bởi Định tuyến

  3. Query strings: Phần chuỗi truy vấn của URI.

Nguồn: Làm thế nào mô hình ràng buộc hoạt động


FYI, bạn cũng có thể kết hợp các phương pháp tự động và rõ ràng:

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

20

Bạn chỉ có thể tạo một đối tượng như thế này:

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

Và sau đó trong bộ điều khiển chỉ cần làm một cái gì đó như thế:

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

Thậm chí tốt hơn, bạn có thể tạo mô hình API từ:

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

đến:

[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 này sẽ áp dụng cho cái gì? Tôi chưa quen với điều này vì vậy tôi không thể chuyển đổi kỹ sư về phía trước với URL. Nó sẽ giống như example.com/somequery/ trên ?
Christian

1
@Christian nếu bạn không thay đổi bất kỳ quy ước, nó sẽ là example.com/[controller]/[action]/{someid:int}?someparameter=1&someparameter2=2
LxL

19

Đây là mẫu mã tôi đã sử dụng (với chế độ xem .NET Core):

@{
    Microsoft.Extensions.Primitives.StringValues queryVal;

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

2
Upvote để bao gồm tên đối tượng FULL (hoặc câu lệnh sử dụng đúng). Ổ đĩa cho tôi khi mọi người chỉ đặt tên đối tượng mà không có sự cố hoàn toàn hoặc ít nhất là một tuyên bố sử dụng. Cảm ơn.
granadaCoder

11

StringValueslà một chuỗi các chuỗi . Bạn có thể nhận được giá trị chuỗi của bạn bằng cách cung cấp một chỉ số, ví dụ HttpContext.Request.Query["page"][0].


1
Cảm ơn bạn; đây là câu trả lời duy nhất thực sự trả lời câu hỏi (Trong trường hợp của tôi, tôi không thể sử dụng ràng buộc vì tôi có logic phức tạp hơn như "trước tiên hãy thử chuỗi truy vấn, nếu thiếu, hãy thử phiên và v.v."
Marcel Popescu

7

IQueryCollectioncó một TryGetValue()giá trị trả về một giá trị với khóa đã cho. Vì vậy, nếu bạn có một tham số truy vấn được gọi someInt, bạn có thể sử dụng nó như vậy:

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

Lưu ý rằng trừ khi bạn có nhiều tham số cùng tên, StringValuesloại không phải là vấn đề.


Để thêm vào câu trả lời này, nếu bạn gọi StringValues.ToString (), bạn có thể truyền trực tiếp vào chuỗi nếu đó là những gì bạn cần.
eltiare

Độc giả tương lai: tên đủ điều kiện "Microsoft.AspNetCore.Http.IQueryCollection queryString = this.Request.Query;" Của tôi là trong "Hội Microsoft.AspNetCore.Http.Features, Version = 3.1.0.0" và "Microsoft.Extensions.Primologists.StringValues" (của tôi là trong "Hội Microsoft.Extensions.Primologists, Version = 3.1.2.0,")
granadaCoder

3

trong lõi .net nếu bạn muốn truy cập chuỗi truy vấn trong chế độ xem của chúng tôi, hãy sử dụng nó như

@Context.Request.Query["yourKey"]

nếu chúng tôi ở vị trí mà @Context không có sẵn, chúng tôi có thể tiêm như thế

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

cũng cho cookie

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

2
Không cần tất cả mã đó. Chỉ cần sử dụng @ Context.Request.Query ["yourKey"]
Shadi Namrouti

Có ...
M.Ali El-Sayed

2

Tôi có một giải pháp tốt hơn cho vấn đề này,

  • request là thành viên của lớp trừu tượng ControllerBase
  • GetSearchParams () là một phương thức mở rộng được tạo trong lớp người trợ giúp dưới đây.

var searchparams = await Request.GetSearchParams();

Tôi đã tạo một lớp tĩnh với một vài phương thức mở rộng

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;
    }
}

bằng cách này bạn có thể dễ dàng truy cập tất cả các thông số tìm kiếm của bạn. Tôi hy vọng điều này sẽ giúp nhiều nhà phát triển :)


Tôi có thiếu thứ gì không - FhirException được định nghĩa ở đâu, không gian tên là Nhiệm vụ <SearchParams> được tìm thấy trong?
Doug Thompson - DouggyFresh

1

Một số ý kiến ​​cũng đề cập đến điều này, nhưng asp net core thực hiện tất cả công việc này cho bạn.

Nếu bạn có một chuỗi truy vấn khớp với tên, nó sẽ có sẵn trong bộ điều khiển.

https: // myapi / some-endpoint / 123? someQueryString = Yay ThisWorks

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

Ouputs:

123

Yay ThisWorks

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.