如何在C#中将查询字符串添加到HttpClient.BaseAddress?

4

我将尝试将查询字符串传递到BaseAddress中,但它无法识别引号“?”。

这个引号会破坏URI。

首先,我创建了我的BaseAddress。

httpClient.BaseAddress = new Uri($"https://api.openweathermap.org/data/2.5/weather?appid={Key}/"); 

然后我调用GetAsync方法,尝试添加另一个参数。

using (var response = await ApiHelper.httpClient.GetAsync("&q=mexico"))....

这是代码调用的URI

https://api.openweathermap.org/data/2.5/&q=mexico

1
可能是Build query string for System.Net.HttpClient get的重复问题。 - Carl Pease
我认为如果你想有效地使用BaseAddress属性,你需要使用以System.Uri作为参数的GetAsync方法。它将解析您的部分URL并将其附加到基础URL上。您的查询字符串应该以问号?q=mexico&other=2开头。 - Glenn Ferrie
我会倾向于创建一个DelegatingHandler,因为我认为这个功能不可能在没有处理程序或在每个请求中手动附加到URL的情况下实现。 - ProgrammingLlama
嗨,您对这个问题还有什么不确定的地方吗? - ProgrammingLlama
2个回答

5

如果你需要对每个请求应用API密钥,我建议使用DelegatingHandler

private class KeyHandler : DelegatingHandler
{
    private readonly string _escapedKey;

    public KeyHandler(string key)  : this(new HttpClientHandler(), key)
    {
    }

    public KeyHandler(HttpMessageHandler innerHandler, string key) : base(innerHandler)
    {
        // escape the key since it might contain invalid characters
        _escapedKey = Uri.EscapeDataString(key);
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // we'll use the UriBuilder to parse and modify the url
        var uriBuilder = new UriBuilder(request.RequestUri);

        // when the query string is empty, we simply want to set the appid query parameter
        if (string.IsNullOrEmpty(uriBuilder.Query))
        {
            uriBuilder.Query = $"appid={_escapedKey}";
        }
        // otherwise we want to append it
        else
        {
            uriBuilder.Query = $"{uriBuilder.Query}&appid={_escapedKey}";
        }
        // replace the uri in the request object
        request.RequestUri = uriBuilder.Uri;
        // make the request as normal
        return base.SendAsync(request, cancellationToken);
    }
}

使用方法:

httpClient = new HttpClient(new KeyHandler(Key));
httpClient.BaseAddress = new Uri($"https://api.openweathermap.org/data/2.5/weather"); 

// since the logic of adding/appending the appid is done based on what's in
// the query string, you can simply write `?q=mexico` here, instead of `&q=mexico`
using (var response = await ApiHelper.httpClient.GetAsync("?q=mexico"))

** 注意:如果您正在使用ASP.NET Core,应调用 services.AddHttpClient(),然后使用IHttpHandlerFactory生成KeyHandler的内部处理程序。


你能推荐一些在 .NET Core 中实现这个的例子吗?你是指简单地调用 .AddHttpMessageHandler<KeyHandler>() 吗? - tappetyclick
同样想知道,您能详细解释一下您回答的最后一部分吗? - silkfire

0
这是我解决它的方式:
Http客户端实现:
namespace StocksApi2.httpClients
{
    public interface IAlphavantageClient
    {
        Task<string> GetSymboleDetailes(string queryToAppend);
    }

    public class AlphavantageClient : IAlphavantageClient
    {
        private readonly HttpClient _client;

        public AlphavantageClient(HttpClient httpClient)
        {
            httpClient.BaseAddress = new Uri("https://www.alphavantage.co/query?apikey=<REPLACE WITH YOUR TOKEN>&");
            httpClient.DefaultRequestHeaders.Add("Accept", "application/json; charset=utf-8");
            httpClient.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");

            _client = httpClient;
        }

        public async Task<string> GetSymboleDetailes(string queryToAppend)
        {
            _client.BaseAddress = new Uri(_client.BaseAddress + queryToAppend);
            return await _client.GetStringAsync("");
        }
    }
}

控制器:

namespace StocksApi2.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class SymbolDetailsController : ControllerBase
    {
        private readonly IAlphavantageClient _client;

        public SymbolDetailsController(IAlphavantageClient client)
        {
            _client = client;
        }


        [HttpGet]
        public async Task<ActionResult> Get([FromQuery]string function = "TIME_SERIES_INTRADAY",
            [FromQuery]string symbol = "MSFT", [FromQuery]string interval = "5min")
        {

            try {
                string query = $"function={function}&symbol={symbol}&interval={interval}";
                string result = await _client.GetSymboleDetailes(query);
                return Ok(result);
            }catch(Exception e)
            {
                return NotFound("Error: " + e);
            }

        }
    }
}

在 Startup.cs 文件的 ConfigureServices 方法中:

  services.AddHttpClient();
  services.AddHttpClient<IAlphavantageClient, AlphavantageClient>();

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