не может создать объем услуг в конструкторе репозитория asp.net core - PullRequest
2 голосов
/ 29 марта 2019

У меня есть служба временного хранилища, и мне нужно создавать набор служб каждый раз, когда я ее вызываю.

Я пытался создать эту область в конструкторе хранилища следующим образом:

public class ServiceRepository : IServiceRepository
{
    private IServiceScopeFactory _serviceScopeFactory;
    private IServiceScope _scope;
    private IServiceProvider _serviceContainer;

    private DataBaseContext _db;

    public ServiceRepository(DataBaseContext context, IServiceScopeFactory serviceScopeFactory)
    {
        _db = context;
        _serviceScopeFactory = serviceScopeFactory;
        _scope = _serviceScopeFactory.CreateScope();
        _serviceContainer = _scope.ServiceProvider;
    }

и после этого я попытался позвонить в службу репозитория у поставщика услуг:

var serviceRepository = _serviceProvider.GetRequiredService<IServiceRepository>();

Я ожидаю, что каждый раз, когда я называю этот сервис таким образом, будет создаваться набор сервисов, который я объявил в конструкторе хранилища. Но при доступе к услуге я получаю ошибку:

System.InvalidOperationException: 'Cannot resolve 'Data_Access_Layer.Interfaces.IServiceRepository' from root provider because it requires scoped service 'Data_Access_Layer.EF.DataBaseContext'.'

Что я делаю не так? раньше я установил область видимости следующим образом:

var scopeFactory = _serviceProvider.GetService<IServiceScopeFactory>();
var scope = scopeFactory.CreateScope();
var scopedContainer = scope.ServiceProvider;

Но в этом случае мне нужно объявлять область видимости каждый раз перед вызовом IServiceRepository. Вот почему я хочу объявить область видимости в конструкторе IServiceRepository.

Ответы [ 2 ]

0 голосов
/ 29 марта 2019

Вы используете все это неправильно. Во-первых, временные объекты времени жизни могут быть внедрены непосредственно в сервисы с определенной областью. Вы должны не вводить IServiceProvider или IServiceScopeFactory и т. Д., А скорее свои фактические зависимости. Вы уже внедряете свой контекст напрямую (это сервис с областью действия), поэтому я не уверен, почему вы пытаетесь обрабатывать что-то еще по-другому.

Вы должны вводить IServiceProvider (ничего больше) только тогда, когда ваш объект имеет одноэтапное время жизни и нуждается в сервисах с областью действия. Это называется анти-паттерном сервисного локатора, и это анти-паттерн по причине: вы должны избегать необходимости делать это как можно больше. В общем, большинство из того, что люди считают синглетонами, на самом деле не должно быть синглетонами. Есть только несколько случаев, когда вам действительно нужна одиночная жизнь. Во всех других сценариях "scoped" должен быть вашим началом жизни. Кроме того, если вашему синглтону действительно нужны сервисы с областями действия, это сильный аргумент, что он должен быть сам по себе.

Однако, если вы делаете , попадаете в ситуацию, когда вам действительно нужно одноразовое время жизни и вам все еще нужны сервисы с определенной областью, то правильный способ сделать это следующий:

public class MySingletonService
{
    private readonly IServiceProvider _provider;

    public MySingletonService(IServiceProvider provider)
    {
        _provider = provider;
    }

    ...
}

И это все. Вы не создаете область видимости внутри конструктора. Любая служба, извлеченная из области, существует только в этой области, и когда эта область исчезает, служба тоже. Таким образом, вы не можете сохранять сервисы с ограниченным диапазоном для ивара на одиночном. Вместо этого, внутри каждого отдельного метода, который нуждается в такой услуге, вам нужно сделать:

using (var scope = _provider.CreateScope())
{
    var myScopedService = scope.ServiceProvider.GetRequiredService<MyScopedService>();
    // do something with scoped service
}

Это еще одна причина, по которой сервисный локатор является анти-паттерном: он приводит к большому количеству тупого и повторяющегося кода. Иногда у вас нет выбора, но большую часть времени вы делаете.

0 голосов
/ 29 марта 2019

Я помогаю, просто добавь .UseDefaultServiceProvider(options => options.ValidateScopes = false) к BuildWebHos т в Program.cs вот так:

public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .UseDefaultServiceProvider(options => options.ValidateScopes = false)
            .Build();

Надеюсь, кому-то это тоже будет полезно

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...