繁体   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