我有一个业务流程(BMPN)需要进行两次http调用。第一个用于身份验证,它的主体中包含登录名和密码,其响应包含 cookie。然后我将这些 cookie 放入第二个请求中。基本上,配对的目的首先是进行身份验证,然后上传文件。但是可以有很多这样的文件要上传,每个文件都有自己的业务流程实例,因此可以同时有很多这样的实例。
我的服务目前看起来像这样:
class FileUploadService {
private readonly string _appUrl;
private readonly string _authServiceUrl;
private readonly string _userName;
private readonly string _userPassword;
private readonly IHttpClientFactory _httpClientFactory;
private IEnumerable<string> _cookies;
public FileUploadService(string appUrl, string userName, string userPassword) {
_appUrl = appUrl;
_authServiceUrl = _appUrl + @"/ServiceModel/AuthService.svc/Login";
_userName = userName;
_userPassword = userPassword;
var serviceCollection = new ServiceCollection();
serviceCollection.AddHttpClient("MyHttpClient").ConfigurePrimaryHttpMessageHandler(
configureHandler: () => new HttpClientHandler {
UseCookies = false
});
var serviceProvider = serviceCollection.BuildServiceProvider();
_httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();
}
public void TryAuthnenticate() {
HttpClient httpClient = _httpClientFactory.CreateClient("MyHttpClient");
string requestBody = @"{
""UserName"":""" + _userName + @""",
""UserPassword"":""" + _userPassword + @"""
}";
HttpContent content = new StringContent(requestBody, Encoding.UTF8, "application/json");
HttpResponseMessage response = httpClient.PostAsync(_authServiceUrl, content).Result;
_cookies = response.Headers.SingleOrDefault(header => header.Key == "Set-Cookie").Value;
}
public void TryUploadFile() {
HttpClient httpClient = _httpClientFactory.CreateClient("MyHttpClient");
httpClient.BaseAddress = new Uri(_appUrl);
string filePath = @"C:\Users\defaultUser\Desktop\12345.pdf";
string url = getUrl(filePath);
MultipartFormDataContent content = getContent(filePath);
HttpResponseMessage response = httpClient.PostAsync(url, content).Result;
}
private string getUrl(string fileInfo) {
// some code that returns a string url
return "";
}
private MultipartFormDataContent getContent(string filePath) {
MultipartFormDataContent content = new MultipartFormDataContent();
byte[] fileBytes = File.ReadAllBytes(filePath);
ByteArrayContent fileContent = new ByteArrayContent(fileBytes);
FileInfo fileInfo = new FileInfo(filePath);
content.Add(fileContent, "12345", fileInfo.Name);
long length = fileInfo.Length;
long rangeEnd = length - 1;
content.Headers.Add("Content-Range", $"bytes 0-{rangeEnd}/{length}");
string cookieValue = "";
foreach (var cookie in _cookies) {
var firstCookieParts = cookie.Split(';');
var secondCookieParts = firstCookieParts[0].Split('=');
cookieValue = cookieValue+$"{secondCookieParts[0]}={secondCookieParts[1]}; ";
}
content.Headers.Add("Cookie", cookieValue);
return content;
}
}
我的想法是我的业务流程的每个实例都将像这样使用此服务:
FileUploadService fileUploadService = new FileUploadService("https://myhost.com", "admin", "test");
fileUploadService.TryAuthnenticate();
fileUploadService.TryUploadFile();
代码确实有效,这意味着文件已上传,但我不确定它是否会随着时间的推移而中断。有几件事我特别担心。
我的理解是,由于我需要很多HttpClient并且它们不需要很长时间,所以最好使用IHttpClientFactory。由于 CookieContainer 可以在池之间共享,因此我想摆脱 CookieContainer 并将 cookie 作为标头发送,因此
UseCookies = false
。但是,如果我使用一个带有 UseCookies = false
的静态 HttpClient 并且 cookie 将作为标头发送,会是相同/更好/更差吗?
我实例化IHttpClientFactory的方式正确吗?我能找到的 95% 的信息都是关于 ASP.NET Core 的,但我使用 .NET Core,而且我不被允许将其转换为 ASP.NET Core。所以,我不太了解我这样做的方式是否正确。
IHttpClientFactory 应该是静态的吗?由于将有多个服务实例,因此将有多个 IHttpClientFactory 实例,这感觉不对,但我还没有看到使用静态 IHttpClientFactory 的示例,所以我不确定这是否有什么问题.
添加命名客户端时,我的想法是我需要以某种方式使所有 Http 客户端不使用 CookieContainer,所以我制作了这个 MyHttpClient 客户端。我不明白的是,每次我调用 CreateClient("MyHttpClient") 时,它都会是同一个 HttpClient 实例吗?它会打破拥有多个客户的整个想法吗?如果是这样,我如何让工厂只向我提供 UseCookies 设置为 false 的客户端?
该服务似乎正在工作,但我不确定我是否了解如何使用 HttpClient 和 IHttpClientFactory。我希望这个东西不会耗尽可用的套接字。
好吧,如果您没有对命名的 HttpClient 进行许多自定义配置,并且需要在不同的类中使用这些配置,那么就没有必要使用
IHttpClientFactory
..如果您只有 1 个配置,并且希望使用该服务的所有实例如果客户端具有相同的配置,那么您可以在类中创建 HttpClient 并在那里进行配置。看看这个 https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-8.0#named-clientsIHttpClientFactory
这取决于一个人认为什么是正确的。我想说最好在单独的类中进行服务绑定,在该类中进行 DI 操作,并且您的
FileUploadService
构造函数应该具有 IHttpClientFactory clientFactory
参数。然后,当从 DI 容器请求 FileUploadService
时,您配置的 DependencyResolver 将尝试获取实现 IHttpClientFactory 的类的实例,并将其传递给 FileUploadService
的构造函数。
就你而言,我认为工厂是否静态并不重要,即使你有超过 1 个
FileUploadService
实例。因为您仅使用工厂中的 CreateClient
方法,该方法实际上创建并返回 HttpClient
的新实例。所以你总是会得到一个新的客户端实例。这里更合适的问题是 你应该使用 1 个 HttpClient
实例吗? 关于你可以在这里找到一些有用的信息:
https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
嗯,您实际上可以轻松检查这一点,在调试时只需多次调用它,并在您创建的客户端上使用
Object.ReferenceEquals()
。最后,如果您决定使用 1 个 HttpClient 实例,那么我看不出使用工厂的目的。