HttpClient.BaseAddress的用途是什么,为什么在第一个请求后不能更改它 [英] What is the purpose of HttpClient.BaseAddress and why can't I change it after the first request

查看:557
本文介绍了HttpClient.BaseAddress的用途是什么,为什么在第一个请求后不能更改它的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我们大多数人可能已经读到我们应该重用 HttpClient 的实例,而不是使用 using 和创造新的。这意味着我可以在程序中创建 HttpClient 的单个实例,并使用每个请求的完整uri字符串调用 GetAsync 。这使我进入 HttpClient BaseAddress 属性。请考虑以下代码:

So most of us have probably read that we are supposed to reuse instances of HttpClient instead of using using and creating new ones. That means I can just create a single instance of HttpClient in my program and call GetAsync using a full uri string per request. This leads me to the BaseAddress property of HttpClient. Consider the following code:

HttpClient microsoftClient = new HttpClient() { BaseAddress = new Uri("https://www.microsoft.com/") };
HttpClient stackoverflowClient = new HttpClient() { BaseAddress = new Uri("https://stackoverflow.com/") };

var response = microsoftClient.GetAsync("about").Result;
Console.WriteLine($"I {((response.IsSuccessStatusCode) ? "can" : "cannot")} access microsoft.com/about from the microsoft client");

response = microsoftClient.GetAsync("trademarks").Result;
Console.WriteLine($"I {((response.IsSuccessStatusCode) ? "can" : "cannot")} access microsoft.com/trademarks from the microsoft client");

response = stackoverflowClient.GetAsync("company/about").Result;
Console.WriteLine($"I {((response.IsSuccessStatusCode) ? "can" : "cannot")} access stackoverflow.com/company/about from the stackoverflow client");

response = stackoverflowClient.GetAsync("https://www.microsoft.com/about").Result;
Console.WriteLine($"I {((response.IsSuccessStatusCode) ? "can" : "cannot")} access microsoft.com/about from the stackoverflow client");

microsoftClient.BaseAddress = new Uri("https://stackoverflow.com");
response = microsoftClient.GetAsync("company/about").Result;
Console.WriteLine($"I {((response.IsSuccessStatusCode) ? "can" : "cannot")} access stackoverflow.com/company/about from the microsoft client, after changing the BaseAddress");

直到最后一个代码,该代码运行良好,即使使用stackoverflow <$ c的客户端$ c> BaseAddress 访问Microsoft。但是,当重新分配 BaseAddress 时,此代码在最后一个块的开头抛出 InvalidOperationException ,说明

Up until the last block this code runs fine, even when using the client with the stackoverflow BaseAddress to access Microsoft. However this code throws an InvalidOperationException at the beginning of the last block, when reassigning the BaseAddress, stating

'This instance has already started one or more requests. Properties can only be modified before sending the first request.'

这导致我遇到以下问题:

This leads me to the following questions:


  1. 完全使用 BaseAddress 有什么好处?我可以始终在 GetAsync 调用中使用完整地址。是否只是为了方便/高效而不必构建完整的请求字符串?我的猜测是,它将仅在内部创建单个 ServicePoint ,如此博客帖子(或类似的帖子已经很老了)。

  2. 内部发生的情况是,在发送第一个后,我们无法更改 HttpClient 的属性,尤其是 BaseAddress 请求?如果使用此属性实际上会带来好处,这似乎非常不便。

  1. What is the benefit of using BaseAddress at all? I could just always use the full address in my GetAsync call. Is it just for the convenience/performance of not having to build the the full request string? My guess was that it would only create a single ServicePoint internally as described in the first paragraph of this blog post (or something similar as the post is quite old).
  2. What happens internally that we can't change a property of HttpClient, especially BaseAddress, after sending the first request? This seems quite inconvenient if using this property actually yields benefits.


推荐答案

对于(1),一个常见的用例是与一台服务器进行交互的客户端。也许是该客户端使用的后端API。确切的详细信息将存储在客户端在启动过程中读取的配置文件中。

For (1), a common use case would be a client which interacts with exactly one server. Maybe it's the back-end API that this client was built to use. The exact details will be stored in a config file that the client reads during startup.

我们可以直接访问配置来填充代码,也可以注入从中读取的字符串配置到需要构建完整URL的每个位置。或者,我们可以只配置要放入我们的Dependency Injection容器中的HttpClient的 BaseAddress ,而只需让使用位置注入该对象即可。对于我来说,这是一个预期中的用例。

We could litter our code with direct accesses to the config, or inject the string read from config into every place that needs to construct a full URL. Or we could just configure the BaseAddress of the HttpClient we're putting into our Dependency Injection container and just let the consuming locations have that object injected. That for me is a somewhat expected use case.

对于(2),我认为没有技术限制。我认为这更多的是要使人们摆脱自己。由于设置了 BaseAddress 并导致实际的请求通过例如 GetAsync 是单独的操作,两个单独的代码段同时做这样的事情是不安全的-您很容易就引起了比赛。因此,如果一开始不允许此类竞争,则更容易想到可能共享 HttpClient 的单个实例的多线程程序。

For (2), I don't think there's a technical limitation. I think this is more there to save people from themselves. Since setting a BaseAddress and causing an actual request to go out via e.g. GetAsync are separate actions, it would be unsafe for two separate pieces of code to be doing such a thing at the same time - you could easily get races. So it's easier to reason about multi-threaded programs that may be sharing a single instance of HttpClient if such races aren't allowed in the first place.

这篇关于HttpClient.BaseAddress的用途是什么,为什么在第一个请求后不能更改它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆