Rest 带有DI的.Net Core 1.1 HttpClient
以下是我正在使用的代码:Rest 带有DI的.Net Core 1.1 HttpClient,rest,singleton,asp.net-core-1.0,Rest,Singleton,Asp.net Core 1.0,以下是我正在使用的代码: namespace MySite.Api { using System.Collections.Specialized; using System.Linq; using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Configurat
namespace MySite.Api
{
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System;
using System.Net.Http.Headers;
using Microsoft.Extensions.Logging;
/// <summary>
/// API query execution helper
/// </summary>
public class ApiQuery : IApiQuery
{
/// <summary>
/// configuration reference
/// </summary>
private IConfiguration config;
private HmacAuthenticationUtils hmacUtils;
private readonly ILogger logger;
private static readonly HttpClient httpClient = new HttpClient();
private static readonly HttpClient httpClientHMAC = new HttpClient();
/// <summary>
/// Initializes a new instance of the <see cref="ApiQuery"/> class.
/// </summary>
/// <param name="inConfig">injected configuration</param>
public ApiQuery(IConfiguration inConfig, HmacAuthenticationUtils hmacUtils, ILoggerFactory loggerFactory)
{
this.config = inConfig;
this.hmacUtils = hmacUtils;
this.logger = loggerFactory.CreateLogger("perfLogger");
}
/// <summary>
/// HTTP verb post
/// </summary>
/// <param name="requestUrl">API url</param>
/// <param name="requestData">request data</param>
/// <returns>HTTP response message</returns>
public virtual async Task<string> Post(string requestUrl, object requestData, HttpClient client = null)
{
return await PostBypassCache(requestUrl, requestData, client);
}
/// <summary>
/// HTTP verb post, specifically to bypass cache
/// </summary>
/// <param name="requestUrl">API url</param>
/// <param name="requestData">request data</param>
/// <returns>HTTP response message</returns>
public async Task<string> PostBypassCache(string requestUrl, object requestData, HttpClient client = null)
{
DateTime perfStart = DateTime.Now;
string customerJson = string.Empty;
if (requestData is string)
{
customerJson = requestData.ToString();
}
else
{
customerJson = JsonConvert.SerializeObject(requestData);
}
////just some template output to test which I'm getting back.
string resultJson = "{ 'status':'No Content'}";
if (client == null)
{
client = httpClient;
}
var response = await httpClient.PostAsync(requestUrl, new StringContent(customerJson, Encoding.UTF8, "application/json"));
if (response.StatusCode == HttpStatusCode.OK)
{
resultJson = await response.Content.ReadAsStringAsync();
}
logger.LogInformation("response time: " + (DateTime.Now - perfStart).TotalMilliseconds + "ms. Resource:" + requestUrl);
return resultJson;
}
/// <summary>
/// HTTP verb post
/// </summary>
/// <param name="requestUrl">API url</param>
/// <param name="requestData">request data</param>
/// <param name="headerset">header data</param>
/// <returns>string data</returns>
public async Task<string> PostHmacAuth(string requestUrl, string requestData)
{
var httpRequest = new HttpRequestMessage(HttpMethod.Post, requestUrl);
httpRequest.Content = new StringContent(requestData, Encoding.UTF8, "application/json");
var signature = await Utils.GenerateAuthenticationString(httpRequest);
httpClientHMAC.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(HmacAuthenticationUtils.HmacHeader, signature);
return await PostBypassCache(requestUrl, requestData, httpClientHMAC);
}
}
}
名称空间MySite.Api
{
使用System.Collections.Specialized;
使用System.Linq;
Net系统;
使用System.Net.Http;
使用系统文本;
使用System.Threading.Tasks;
使用Microsoft.Extensions.Configuration;
使用Newtonsoft.Json;
使用制度;
使用System.Net.Http.Header;
使用Microsoft.Extensions.Logging;
///
///API查询执行助手
///
公共类ApiQuery:IApiQuery
{
///
///配置参考
///
私有IConfiguration配置;
私人HmacAuthenticationUtils hmacUtils;
专用只读ILogger记录器;
私有静态只读HttpClient HttpClient=新HttpClient();
私有静态只读HttpClient httpClientHMAC=新HttpClient();
///
///初始化类的新实例。
///
///注入配置
公共ApiQuery(图中的IConfig配置、HmacAuthenticationUtils hmacUtils、iLogger工厂和loggerFactory)
{
this.config=inConfig;
this.hmacUtils=hmacUtils;
this.logger=loggerFactory.CreateLogger(“perfLogger”);
}
///
///HTTP动词post
///
///API url
///请求数据
///HTTP响应消息
公共虚拟异步任务Post(字符串requestUrl,对象requestData,HttpClient=null)
{
返回等待缓存(requestUrl、requestData、客户端);
}
///
///HTTP谓词post,专门用于绕过缓存
///
///API url
///请求数据
///HTTP响应消息
公共异步任务PostBypassCache(字符串requestUrl,对象requestData,HttpClient客户端=null)
{
DateTime perfStart=DateTime.Now;
string customerJson=string.Empty;
if(请求数据为字符串)
{
customerJson=requestData.ToString();
}
其他的
{
customerJson=JsonConvert.SerializeObject(requestData);
}
////只是一些要测试的模板输出,我正在返回。
字符串resultJson=“{'status':'No Content'}”;
if(客户端==null)
{
client=httpClient;
}
var response=wait-httpClient.PostAsync(requestUrl,newstringcontent(customerJson,Encoding.UTF8,“application/json”);
if(response.StatusCode==HttpStatusCode.OK)
{
resultJson=await response.Content.ReadAsStringAsync();
}
logger.LogInformation(“响应时间:”+(DateTime.Now-perfStart).totalmillizes+“ms.Resource:”+requestUrl);
返回resultJson;
}
///
///HTTP动词post
///
///API url
///请求数据
///标题数据
///字符串数据
公共异步任务PostHmacAuth(字符串requestUrl,字符串requestData)
{
var httpRequest=新的HttpRequestMessage(HttpMethod.Post,requestUrl);
httpRequest.Content=newstringcontent(requestData,Encoding.UTF8,“application/json”);
var signature=wait Utils.GenerateAuthenticationString(httpRequest);
httpClientHMAC.DefaultRequestHeaders.Authorization=新的AuthenticationHeaderValue(HmacAuthenticationUtils.HmacHeader,签名);
return wait-PostBypassCache(requestUrl、requestData、httpClientHMAC);
}
}
}
在Startup.cs中,我注入它
services.AddTransient<IApiQuery, ApiQuery>();
services.AddTransient();
我最近做了这些更改,因为之前代码实际上是在每个方法中实例化httpClient,即。,
var client=新的HttpClient()
在某些地方,它就像:
正在使用(var client=new HttpClient()){}
我认为由于这样的代码,appPool显示了我的IIS挂起的错误,只有重新启动appPool才能解决这个问题。我总结说这是一个问题,因为我阅读了很多其他文章。我无法得出的结论是,将ApiQuery服务作为singleton本身注入是否是一个好主意。
把它作为一种药物注射会更好吗
由于我现在将IApiQuery作为临时服务注入到每个业务服务中,这是个好主意吗?任何想法
HttpClient
都应该是单例范围的。您的计算机上可用的连接数量有限,而且由于HttpClient
保留了它创建的连接,因此多个实例的浮动会很快耗尽您的连接池
从ASP.NET Core 2.1开始,就有了IHttpClientFactory
,它提供了一种简单且可重用的方法来注入范围适当的HttpClient
实例。但是,由于您使用的是1.1,因此无法使用。建议的路径是将项目升级到2.1。ASP.NET核心的1.X行显然是垃圾。它还没有准备好投入生产使用,尽管它是官方发布的
如果坚持使用1.1,则需要实现自己的重用HttpClient
实例的方法。最直接的方法是使用“accessor”类,然后可以利用这些类将不同的HttpClient
s注入到不同的对象中。例如:
public class ApiHttpClientAccessor : IDisposable
{
public ApiHttpClientAccessor()
{
HttpClient = new HttpClient
{
BaseAddress = new Uri("https://foo.com")
};
}
public HttpClient HttpClient { get; }
private bool _disposed;
public virtual void Dispose(bool disposing)
{
if (disposing && !_disposed)
{
HttpClient.Dispose();
}
_disposed = true;
}
public bool Dispose() =>
Dispose(true);
}
然后,您可以将这个访问器类注册为单例,这意味着它只会创建一次(因此包含的HttpClient
也只会创建一次)。然后,设置类以在其构造函数中接受此访问器:
public class ApiQuery : IApiQuery
{
private readonly HttpClient _client;
public ApiQuery(ApiHttpClientAccessor httpClientAccessor)
{
_client = (httpClientAccessor ?? throw new ArgumentNullException(nameof(httpClientAccessor))).HttpClient;
}
...
}
在Startup.cs
中:
services.AddSingleton<ApiHttpClientAccessor>();
services.AddTransient<IApiQuery, ApiQuery>();
services.AddSingleton();
services.AddTransient();
感谢您的回答。迁移正在进行中,但至少需要2个月才能投入生产。我想