Не удается разрешить зависимость в пользовательском атрибуте ValidationAttribute, IServiceProvider имеет значение null в параметре ValidatationContontext.

Приложение ASP.NET Core 2.1 MVC, использующее Autofac в соответствии с их документацией по установке (https://autofaccn.readthedocs.io/en/latest/integration/aspnetcore.html).

Я пытаюсь разрешить зависимость в пользовательском атрибуте ValidationAttribute. Возвращаемое значение из valicationContext.GetService всегда возвращает значение null. При проверке validatationContext частный член serviceProvider всегда имеет значение null.

что мне не хватает в настройке, что это не работает. Зависимости разрешаются везде в приложении, но не в атрибутах ValidationAttributes.

public class MyCustomAttribute : ValidationAttribute
{

    public MyCustomAttribute ()
    {

    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        // THIS IS ALWAYS RETURNING NULL
        var IMyService service = (IMyService)validationContext.GetService(typeof(IMyService));

        return ValidationResult.Success;
    }
}



Ответы (1)


Я не могу сказать, что пробовал это раньше, но, выполнив поиск, я нашел эту проблему что, по-видимому, указывает на то, что поставщик услуг (не свойство ServiceContainer, а поставщик услуг, который будет отвечать на вызовы GetService) всегда должен быть заполнен. Конечно, это из архивного репозитория с самого начала .NET Core, но он все еще должен храниться.

Глядя на источник для ValidationContext Я вижу, что приватное поле serviceProvider на самом деле является функцией, экземпляр которой нужно где-то создать; на самом деле это не ссылка на самого провайдера. Это означает, что если он равен нулю, происходит одно из двух:

  1. Путь через ASP.NET Core, который создает экземпляр ValidationContext, не проходит через IServiceProvider, необходимый для предоставления услуг.
  2. Что-то сломано.

Если это # ​​1, я предполагаю, что есть множество потенциальных причин. Я бы подумал о таких вещах, как...

  • Атрибут используется чем-то, работающим за пределами «Конвейера ASP.NET» — например, вызываемой вручную проверкой или, возможно, чем-то при запуске приложения, где в данный момент нет запроса.
  • Атрибут используется в тесте, где не действует полный конвейер.

Что-то такое. Я не говорю, что это то, что происходит, но я уже видел подобные вопросы, когда появляется что-то работает неправильно, хотя на самом деле это проблема кода приложения. Например, есть много вопросов о том, почему не работают зависимости «экземпляр на запрос», и оказывается, что код выполняется в фоновом потоке, где нет запроса, так что... да . Я не знаю, как работает ваше приложение, но здесь в игру вступает что-то вроде «Я делаю что-то, о чем забыл упомянуть, потому что не думаю, что это актуально».

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

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

Установите точку останова на неудачном операторе, а затем переключитесь в окно «стека вызовов» Visual Studio. Щелкните кадры стека вызовов выше в стеке и посмотрите, что на самом деле создает этот объект контекста. С небольшим щелчком и интуицией вы, вероятно, сможете понять, в чем проблема. Возможно, это укажет на что-то в вашем приложении, о чем вы не подозревали, может быть, это укажет на ошибку в ASP.NET Core. Если это ошибка в ASP.NET Core, информация, которую вы нашли во время сеанса отладки, будет очень полезна для этой команды.

Наконец, я был бы упущен, если бы не упомянул, что ручное разрешение службы в таком атрибуте технически является расположением службы, а не внедрением зависимостей, и это было бы лучшим универсальным решением, если бы вы полностью избегали этого. Здесь очень похож на ваш вопрос как обойти это с помощью Simple Injector, хотя этот принцип верен и для Autofac. Настройка валидаторов модели и использование поставщика валидатора модели, а не атрибутов, может быть лучшим и более проверяемым способом. Ответ на этот вопрос содержит больше пояснений по этому поводу.

person Travis Illig    schedule 10.01.2020