IMO, эта новая функция в веб-формах не очень хорошо продумана.Основная проблема заключается в том, что веб-формы нарушают контракт IServiceProvider
.
Метод IServiceProvider.GetService
определяет, что null
должен быть возвращен, если такой службы не существует.Но как только вы на самом деле возвращаете null
, например, когда вы не можете создать этот тип, веб-формы бросают NullReferenceException
из глубины своего стека.
С другой стороны, веб-формы соответствовали быабстракция IServiceProvider
, включающая Simple Injector, была бы вопросом одного утверждения, поскольку SimpleInjector.Container
фактически реализует IServiceProvider
:
// WARNING: This won’t work
HttpRuntime.WebObjectActivator = container;
Кроме того, когда IServiceProvider
через HttpRuntime.WebObjectActivator
веб-формы будут вызывать его практически для всего, даже для своих внутренних объектов, что, на мой взгляд, не имеет большого смысла.
Поэтому вместо предоставления IServiceProvider
реализации, которая является совместимый с IServiceProvider
контрактом, вам нужно будет предоставить специальную реализацию ASP.NET Web Forms IServiceProvider
(которая поэтому нарушает контракт).
Обратите внимание, что большинство DI-контейнеров на самом деле реализуют IServiceProvider
, но вы увидите, что большинство из них терпят неудачу из-за нарушения контракта.
Реализация адаптера будет выглядеть следующим образом:
class SimpleInjectorWebFormsServiceActivator : IServiceProvider
{
private const BindingFlags flag =
BindingFlags.Instance | BindingFlags.NonPublic |
BindingFlags.Public | BindingFlags.CreateInstance;
private readonly Container container;
public SimpleInjectorWebFormsServiceActivator(Container container) =>
this.container = container;
public object GetService(Type serviceType) =>
serviceType.GetConstructors().Length > 0
? this.container.GetInstance(serviceType)
: Activator.CreateInstance(serviceType, flag, null, null, null);
}
И может быть установлен следующим образом:
HttpRuntime.WebObjectActivator =
new SimpleInjectorWebFormsServiceActivator(container);
Эта реализация проверяет, содержит ли тип открытые конструкторы, и если да, то делегирует вызов Simple Injector, который будет создавать тип.В противном случае он будет использовать Activator.CreateInstance
для создания типа.
Обратите внимание, что при использовании этой реализации вам не нужно custom IConstructorSelectionBehavior
, поэтому вы можете полностью удалить InternalConstructorResolutionBehavior
.