使用 HttpClient 处理这种类型的通用方法是使用 HttpMessageHandler ,就像您可能要做的其他工作一样,例如添加授权标头、签署消息等。
我还使用基于 Task 的语法重写了它,因为它更符合 HttpClient 的理念——调用者可以根据需要调用 .Result 。
private await Task<System.IO.Stream> Upload(string url, string param1, Stream fileStream, byte[] fileBytes)
{
HttpContent stringContent = new StringContent(param1);
HttpContent fileStreamContent = new StreamContent(fileStream);
HttpContent bytesContent = new ByteArrayContent(fileBytes);
var handler = new HttpClientHandler();
var md5Handler = new RequestContentMd5Handler();
md5Handler.InnerHandler = handler;
using (HttpClient client = new HttpClient(md5Handler))
{
using (MultipartFormDataContent formData = new MultipartFormDataContent())
{
formData.Add(stringContent, "param1", "param1");
formData.Add(fileStreamContent, "file1", "file1");
formData.Add(bytesContent, "file2", "file2");
using (var response = await client.PostAsync(url, formData))
{
if (!response.IsSuccessStatusCode)
{
return null;
}
return await response.Content.ReadAsStreamAsync();
}
}
}
}
此外,在每个请求上重新创建 HttpClient 通常是不好的做法(请参阅在 WebAPI 客户端中每次调用创建一个新的 HttpClient 的开销是多少?等),但我将其保留在此处以符合问题。
这是使用的处理程序...
/// <summary>
/// Handler to assign the MD5 hash value if content is present
/// </summary>
public class RequestContentMd5Handler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Content == null)
{
return await base.SendAsync(request, cancellationToken);
}
await request.Content.AssignMd5Hash();
var response = await base.SendAsync(request, cancellationToken);
return response;
}
}
以及扩展方法...
/// <summary>
/// Compute and assign the MD5 hash of the content.
/// </summary>
/// <param name="httpContent"></param>
/// <returns></returns>
public static async Task AssignMd5Hash(this HttpContent httpContent)
{
var hash = await httpContent.ComputeMd5Hash();
httpContent.Headers.ContentMD5 = hash;
}
/// <summary>
/// Compute the MD5 hash of the content.
/// </summary>
/// <param name="httpContent"></param>
/// <returns></returns>
public static async Task<byte[]> ComputeMd5Hash(this HttpContent httpContent)
{
using (var md5 = MD5.Create())
{
var content = await httpContent.ReadAsStreamAsync();
var hash = md5.ComputeHash(content);
return hash;
}
}
使对各个部分进行单元测试变得容易。