![](/img/trans.png)
[英]Replace a service in servicecollection used by webhost in .net core
[英]Service is not registered in the servicecollection
我不明白为什么在将服务添加到IServiceCollection
,当我尝试使用ServiceProvider
对它的引用时,该值为null。
启动
public void ConfigureServices(IServiceCollection services)
{
Startup.ConfigureServicesForDebugging?.Invoke(services);
try
{
services.AddTransient<HttpWrapper>();
ServiceProvider prov = services.BuildServiceProvider();
HttpWrapper returned=prov.GetRequiredService<HttpWrapper>();
if (returned == null)
{
Console.WriteLine("is null");
}
else Console.WriteLine(returned.Test);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
HttpWrapper
public class HttpWrapper
{
public HttpClient cl = new HttpClient();
public string Test = "aaa";
}
为什么返回的服务为空? 我首先以为是因为它是Transient
所以它是每个请求的。所以在此阶段没有请求-> null。
但是当也使用AddSingleton
时,它仍然返回null。 为什么该服务为空?
PS我需要的是:
public class TransientService{
public HttpClient sharedProperty;
}
public void ConfigureServices(IServiceCollection services)
{
HttpClient client=new HttpClient();
services.AddTransient( new TransientService{ sharedProperty=client});
}
我需要一个临时的服务,但其所有实例共享一个字段(以我的情况为HttpClient
)
PS 2从GetService
更改为GetRequiredService
我收到未注册该服务的InvalidOperationException
为什么会这样? 我也从改为非lambda插入:
services.AddTransient()仍然存在相同的问题。
我无法重现该问题。
如果尚未注册请求的服务,则GetService
将返回null。 如果GetRequiredService
,它将引发异常。
这段代码有两个问题。
首先,这行:
services.AddTransient(y =>wrapper);
注册一个工厂函数 ,该函数返回相同的HttpWrapper实例,而不是HttpWrapper实例本身。 该函数将返回wrapper
包含的内容。
其次, AddTransient
说这是一个临时服务,但是每次都会返回相同的实例。
如果每次都使用相同的服务,则注册应使用AddSingleton
:
services.AddSingleton<HttpWrapper>();
如果每次都需要一个新实例,则应为:
services.AddTransient<HttpWrapper>();
测试代码
我用此代码测试了问题,无法重现:
static void Main(string[] args)
{
IServiceCollection services = new ServiceCollection();
try
{
HttpWrapper wrapper = new HttpWrapper();
services.AddTransient(provider => wrapper);
ServiceProvider prov = services.BuildServiceProvider();
HttpWrapper returned = prov.GetRequiredService<HttpWrapper>();
Console.WriteLine("No problem");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
该类将被创建,没有任何问题。 失败的唯一方法是wrapper
为null。 如果找不到注册,我使用GetRequiredService
强制执行异常。
类型的Http客户端
从评论看来, 真正的问题是如何创建正确使用HttpClient的服务。 重用同一实例将提高性能,因为它将现有的TCP连接保留在连接池中。 尽管它仍然需要定期回收以处理不断变化的DNS地址。 使用瞬态HttpClient不好,但是使用单个HttpClient实例也是如此。
HttpClientFactory通过池化并回收实际对每个HttpClient执行HTTP请求的HttpClientHandler实例来解决这两个问题。 使用HttpClientFactory实施弹性HTTP请求的文章解释了它是如何工作的,但总的来说,只需添加:
services.AddHttpClient<ICatalogService, CatalogService>();
将确保CatalogService
每个实例都将得到正确处理的HttpClient
。 CatalogService
所需要做的就是在其构造函数中接受HttpClient
并在其方法中使用它:
public class CatalogService : ICatalogService
{
private readonly HttpClient _httpClient;
public CatalogService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<Catalog> GetCatalogItems(int page, int take,
int? brand, int? type)
{
....
var responseString = await _httpClient.GetStringAsync(uri);
...
}
}
Microsoft.Extensions.Http包中提供了AddHttpClient
扩展方法。
对此问题进行适应, HttpWrapper
应该在其构造函数中接受HttpClient参数:
public class HttpWrapper
{
private readonly HttpClient _cl;
public HttpWrapper(HttpClient client)
{
_cl=client;
}
public string TestUrl = "aaa";
}
并注册AddHttpClient
:
services.AddHttpClient<HttpWrapper>();
之后,可以通过以下方式解决:
var returned = prov.GetRequiredService<HttpWrapper>();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.