﻿# 如何在 ASP.NET Core 漂亮的建立 Query String 查詢字串

我們在建立含有 Query String 網址時，若是用字串串接的方式來實作，程式碼會相對的比較醜一點。從 ASP.NET Core 1.0 開始，就有好幾個專門用來建立 Query String 的類別，這些類別不但可以提升程式碼的可讀性，所有的 Query String 也都會進行必要的 URL Encode 動作，讓你的網址更符合國際標準，建議可以多加利用。

![An abstract, conceptual banner image representing building query strings in ASP NET Core  Incorporate elements of code snippets, URLs, and query param](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/c13c06bf618f1e122449-404763c0-d27f-444e-a23d-d08c23562dc3.webp)

### 使用 [QueryString](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.querystring?view=aspnetcore-8.0&WT.mc_id=DT-MVP-4015686) 結構

範例程式如下：

```csharp
var authUrl = "https://access.line.me/oauth2/v2.1/authorize";

var qs = new Microsoft.AspNetCore.Http.QueryString();
qs = qs.Add("response_type", "code");
qs = qs.Add("client_id",     config["LINELogin:client_id"]);
qs = qs.Add("redirect_uri",  config["LINELogin:redirect_uri"]);
qs = qs.Add("scope",         config["LINELogin:scope"]);
qs = qs.Add("state",         GenerateNonce());

var url = $"{authUrl}{qs.Value}";
```

> 此結構內建於 ASP.NET Core 的 `Microsoft.AspNetCore.Http` 命名空間中。如需在 Console 專案使用，必須額外安裝 [Microsoft.AspNetCore.Http.Extensions](https://www.nuget.org/packages/Microsoft.AspNetCore.Http.Extensions) 套件。

### 使用 [QueryBuilder](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.extensions.querybuilder?view=aspnetcore-5.0&WT.mc_id=DT-MVP-4015686) 類別

範例程式如下：

```csharp
var authUrl = "https://access.line.me/oauth2/v2.1/authorize";

var qb = new QueryBuilder();
qb.Add("response_type", "code");
qb.Add("client_id",     config["LINELogin:client_id"]);
qb.Add("redirect_uri",  config["LINELogin:redirect_uri"]);
qb.Add("scope",         config["LINELogin:scope"]);
qb.Add("state",         GenerateNonce());

var url = $"{authUrl}{qb.ToQueryString().Value}";
```

> 此類別內建於 [Microsoft.AspNetCore.Http.Extensions](https://www.nuget.org/packages/Microsoft.AspNetCore.Http.Extensions) 套件中。

### 使用 [QueryHelpers](https://learn.microsoft.com/zh-tw/dotnet/api/microsoft.aspnetcore.webutilities.queryhelpers?view=aspnetcore-6.0&WT.mc_id=DT-MVP-4015686) 類別

範例程式如下：

```csharp
var authUrl = "https://access.line.me/oauth2/v2.1/authorize";

var query = new Dictionary<string, string>
{
    ["response_type"] = "code",
    ["client_id"]     = config["LINELogin:client_id"],
    ["state"]         = GenerateNonce(),
    ["scope"]         = config["LINELogin:scope"],
    ["redirect_uri"]  = config["LINELogin:redirect_uri"],
};

var url = QueryHelpers.AddQueryString(authUrl, query);
```

> 此類別內建於 [Microsoft.AspNetCore.WebUtilities](https://www.nuget.org/packages/Microsoft.AspNetCore.WebUtilities) 套件中。

若要用 .NET 解析完整的網址，通常用 Model Binding 就可以做到，但你若真的需要手動解析網址，可以參考以下範例程式：

```csharp
var authUrl = "https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id=111111&state=222&scope=profile%20openid%20email&redirect_uri=https%3A%2F%2Flocalhost%3A7133%2Fcallback";

var uri = new Uri(authUrl);

// https://access.line.me/oauth2/v2.1/authorize
var uriPath = uri.GetLeftPart(UriPartial.Path);

// ?response_type=code&client_id=111111&state=222&scope=profile%20openid%20email&redirect_uri=https%3A%2F%2Flocalhost%3A7133%2Fcallback"
var uriQuery = uri.GetLeftPart(UriPartial.Query);
var uriQuery = uri.Query;

// https://
var uriScheme = uri.GetLeftPart(UriPartial.Scheme);

// // https://access.line.me
var uriAuthority = uri.GetLeftPart(UriPartial.Authority);

// using Microsoft.AspNetCore.WebUtilities;
var query = QueryHelpers.ParseQuery(uri.Query);

var client_id = query["client_id"].ToString();
```

### 相關連結

-   [c# - Build query string for System.Net.HttpClient get - Stack Overflow](https://stackoverflow.com/questions/17096201/build-query-string-for-system-net-httpclient-get/26744471#26744471)
-   [Uri.GetLeftPart(UriPartial) Method](https://learn.microsoft.com/en-us/dotnet/api/system.uri.getleftpart?view=net-6.0&WT.mc_id=DT-MVP-4015686)
-   [QueryHelpers 類別 (Microsoft.AspNetCore.WebUtilities) | Microsoft Docs](https://learn.microsoft.com/zh-tw/dotnet/api/microsoft.aspnetcore.webutilities.queryhelpers?view=aspnetcore-6.0&WT.mc_id=DT-MVP-4015686)
