HttpClient.BaseAddress的用途是什么,为什么在第一个请求后不能更改它 [英] What is the purpose of HttpClient.BaseAddress and why can't I change it after the first request
问题描述
所以我们大多数人可能已经读到我们应该重用 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:
- 完全使用
BaseAddress
有什么好处?我可以始终在GetAsync
调用中使用完整地址。是否只是为了方便/高效而不必构建完整的请求字符串?我的猜测是,它将仅在内部创建单个ServicePoint
,如此博客帖子(或类似的帖子已经很老了)。 - 内部发生的情况是,在发送第一个后,我们无法更改
HttpClient
的属性,尤其是BaseAddress
请求?如果使用此属性实际上会带来好处,这似乎非常不便。
- What is the benefit of using
BaseAddress
at all? I could just always use the full address in myGetAsync
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 singleServicePoint
internally as described in the first paragraph of this blog post (or something similar as the post is quite old). - What happens internally that we can't change a property of
HttpClient
, especiallyBaseAddress
, 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屋!