![](/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.