Внедрение зависимостей: нет службы для типа - PullRequest
1 голос
/ 16 апреля 2019

Я пытаюсь разделить проблемы по всему приложению, и я подумал, что этот ответ Стивена прекрасно подходит для моего сценария, но я пытаюсь удалить элемент недействительный: Валидация: как добавить оболочку модельного состояния с помощью Ninject?

Я добавил все необходимые классы из ответа.

Я получил свой сервис:

public class PromotionService {
    private readonly IValidationProvider validationProvider;

    public PromotionService(IValidationProvider validationProvider) {
        this.validationProvider = validationProvider;
    }

    public void CreatePromotion(string promoName) {
        //build the model
        Promotion promo = new Promotion() {
            //Name = promoName
        };

        //validate and throw validation exception
        validationProvider.Validate(promo);
    }
}

My ConfigureServices:

        //Register Business Logic services
        services.AddScoped<PromotionService>();

        //get scope factory
        var scopeFactory = services
                .BuildServiceProvider()
                .GetRequiredService<IServiceScopeFactory>();

        ///3668091/validatsiya-kak-dobavit-obolochku-modelnogo-sostoyaniya-s-pomoschy-ninject
        Func<Type, IValidator> validatorFactory = type =>
        {
            var valType = typeof(Validator<>).MakeGenericType(type);
            return (IValidator)scopeFactory.CreateScope().ServiceProvider.GetRequiredService(valType);
        };

        services.AddSingleton<IValidationProvider>(x => new ValidationProvider(validatorFactory));

        services.AddScoped<Validator<Promotion>, PromotionValidator>();

Проблема Я получаю исключение при звонке validationProvider.Validate(promo);

InvalidOperationException: No service for type 'VepoPortal.Services.Validators.Validator`1[VepoCustomerDatabase.Models.Promotion]' has been registered.

Но я зарегистрировал это здесь: services.AddScoped<Validator<Promotion>, PromotionValidator>();

Вопрос Как мне решить эту проблему без использования Ninject?

Редактировать: исправлено с фактическим кодом:

        services.AddScoped<Validator<Promotion>, PromotionValidator>();

        services.AddScoped<IValidationProvider>(sp => {
            Func<Type, IValidator> validatorFactory = type => {
                var valType = typeof(Validator<>).MakeGenericType(type);
                return (IValidator)sp.GetRequiredService(valType);
            };
            return new ValidationProvider(validatorFactory);
        });

1 Ответ

3 голосов
/ 16 апреля 2019
var scopeFactory = services
    .BuildServiceProvider()
    .GetRequiredService<IServiceScopeFactory>();

Таким образом, вы создаете отдельного поставщика услуг и используете его услуги для получения фабрики области обслуживания.

Итак, когда вы позже сделаете следующее:

return (IValidator)scopeFactory.CreateScope().ServiceProvider.GetRequiredService(valType);

Вы используете этого отдельного поставщика услуг.И когда вы разрешаете услуги у этого поставщика услуг, они полностью отделены от тех, в которых ваше приложение выполняется.

И поскольку вы зарегистрировали Validator<Promotion> only после , который вы создалиэтот отдельный поставщик услуг, этот поставщик услуг не будет включать вашу службу валидатора.

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

В вашем случае вы можете получить это, например, изменив регистрацию вашего поставщика услуг проверки:

services.AddSingleton<IValidationProvider>(sp =>
{
    Func<Type, IValidator> validatorFactory = type =>
    {
        var valType = typeof(Validator<>).MakeGenericType(type);
        return sp.GetRequiredService(valType);
    };

    return new ValidationProvider(validatorFactory);
});

sp, который передается на завод, там есть поставщик услуг, один правильный.Таким образом, вы можете использовать это непосредственно для разрешения служб, необходимых для инициализации поставщика.

Вы заметите, что я не создаю новую область обслуживания в пределах validatorFactory.Это связано с тем, что при использовании областей обслуживания вы должны всегда располагать ими после использования.Если вы просто создадите их и разрешите службу из них, тогда область обслуживания останется открытой, и вы можете столкнуться с проблемами позже.

В вашем случае вы не сможете правильно утилизировать область обслуживания, поскольку вам нужновернуть разрешенный объект и захотеть использовать его потом.Так что это означает, что использование области обслуживания здесь не очень хорошая идея.Вам также следует подумать о том, действительно ли вам нужна область обслуживания в целом: ASP.NET Core уже создает область обслуживания для каждого запроса, поэтому имеет смысл просто повторно использовать эту область, если вам действительно нужна зависимость по объему.

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

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