簡體   English   中英

服務未在servicecollection中注冊

[英]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 2GetService更改為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM