Почему я не могу внедрить службу, которая требует httpclient и EF-контекст в контроллере, который требует тот же контекст - PullRequest
0 голосов
/ 12 октября 2018

У меня есть контроллер, которому нужен сервис, поэтому я внедряю его.Службе нужен HttpClient, поэтому я добавляю ее.Им обоим нужен контекст EF.

Я добавляю HttpClient при запуске службы.Однако у меня есть ошибка ниже.

В Startup:

services.AddHttpClient<IMyService, MyService>();

В MyService класс

private readonly HttpClient _httpClient;
private readonly ReadContext _readContext;
public MyService(HttpClient httpClient, ReadContext readContext)
{
    _httpClient = httpClient;
    _readContext = readContext;
}

В моем контроллере:

private readonly IMyService _myService;
public MyController(ReadContext ctx, IMyService myService)
{
    _ctx = ctx;
    _myService = myService;
}

Ошибка:

System.InvalidOperationException: Cannot resolve scoped service 'MyApp.Backend.ReadContext' from root provider.
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.Microsoft.Extensions.DependencyInjection.ServiceLookup.IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
   at lambda_method(Closure , IServiceProvider , Object[] )
   at Microsoft.Extensions.Http.DefaultTypedHttpClientFactory`1.CreateClient(HttpClient httpClient)

Не то, что когда служба внедряется в контроллер, который не требует ReadContext, это работает.Кажется, здесь есть некоторый цикл разрешения.

ОБНОВЛЕНИЕ

Из комментариев я понимаю, что AddHttpClient<T> создает экземпляр T с тем же временем жизни, что и созданный и управляемый HttpClientядром aspnet, которое длиннее, чем время жизни DbContext, которое является временем жизни фактического запроса.Справедливо.Тогда как мне внедрить HttpClient во временную службу?

UPDATE2

В соответствии с этим blog Я могу внедрить экземпляр IHttpClientFactory в MyServiceвместо этого используйте services.AddHttpClient();.На самом деле ошибка исчезает.Мне нужно немного почитать, чтобы понять разницу между запросом у фабрики экземпляра HttpClient или инъекцией.

1 Ответ

0 голосов
/ 12 октября 2018

Зарегистрируйте MyService как область действия:

services.AddScoped<IMyService, MyService>();

И затем просто зарегистрируйте свой HttpClient с помощью MyService:

services.AddHttpClient<MyService>();

То, как вы это делаете сейчас, MyService создается в одноэлементной области видимости, что делает невозможным внедрение зависимостей в области видимости, таких как ваш контекст.

В качестве альтернативы вы можете вместо этого внедрить IServiceProvider и использовать анти-шаблон сервис-локатора, чтобы получить вашконтекст.По какой-то причине это называется анти-паттерном, так что это не самый лучший способ решения проблем, но если ваша служба работает в одиночном режиме, другого пути нет:

public class MyService : IMyService
{
    private readonly HttpClient _client;
    private readonly IServiceProvider _services;

    public MyService(HttpClient client, IServiceProvider services)
    {
        _client = client;
        _services = services;
    }
}

Затем, позже:

using (var scope = _services.CreateScope())
{
    var context = scope.ServiceProvider.GetRequiredService<ReadContext>();
    // do something
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...