更新:
在 Simple Injector 2.5 中,新的RegisterMvcIntegratedFilterProvider
扩展方法已添加到 MVC 集成包中,以替换旧的RegisterMvcAttributeFilterProvider
. 这个新RegisterMvcIntegratedFilterProvider
的包含SimpleInjectorFilterAttributeFilterProvider
下面给出的行为,并允许将属性更好地集成到 Simple Injector 管道中。然而,这确实意味着默认情况下不会注入任何属性,但这可以通过实现自定义 IPropertySelectionBehavior来扩展。建议使用新方法而RegisterMvcIntegratedFilterProvider
不是旧RegisterMvcAttributeFilterProvider
方法,这将[Obsolete]
在将来的版本中标记。
使用RegisterMvcAttributeFilterProvider
扩展方法时,Simple Injector 不会在 MVC 属性上调用任何已注册的初始化程序。如果您在注入的匿名委托中设置断点,NotificationService
您将看到它永远不会被命中。
然而,Simple Injector 确实调用了container.InjectProperties
MVC 属性上的方法,但InjectProperties
会进行隐式属性注入,这意味着它会尝试注入类型上的所有公共属性,但如果无法注入属性(无论出于何种原因),则会跳过它。
我敢打赌,该CriticalErrorAttribute.NotificationService
属性的类型是 ofNotificationService
而不是INotificationService
. 由于您没有NotificationService
显式注册,因此容器将为您创建一个临时实例,这意味着您将获得一个CriticalErrorAttribute
与应用程序其余部分不同的实例。
快速修复:将属性类型更改为INotificationService
.
老实说,我很遗憾曾经为 Simple Injector 实现了 MVC 集成包来使用该InjectProperties
方法。隐式属性注入是非常邪恶的,因为当配置错误时它不会很快失败,我什至考虑InjectProperties
在未来取消对它的支持。然而,问题是许多开发人员都依赖InjectProperties
. 要么直接调用它,要么间接地让容器在 MVC 属性上注入属性。
InjectProperties
不运行任何初始化程序。这是设计使然,还有其他构造允许在不是由容器创建的对象上运行完整的初始化过程。然而问题是,添加它可能会破坏现有客户端,因为这可能导致属性被多次注入。
在你的情况下,我建议一个不同的解决方案:
container.RegisterMvcAttributeFilterProvider()
防止在应用程序的启动路径中调用。这将注册一个特殊FilterAttributeFilterProvider
的内部调用InjectProperties
。您不想使用隐式属性注入,而是想要更明确(和完整)的行为。而是注册以下类:
internal sealed class SimpleInjectorFilterAttributeFilterProvider
: FilterAttributeFilterProvider
{
private readonly ConcurrentDictionary<Type, Registration> registrations =
new ConcurrentDictionary<Type, Registration>();
private readonly Func<Type, Registration> registrationFactory;
public SimpleInjectorFilterAttributeFilterProvider(Container container)
: base(false)
{
this.registrationFactory = type =>
Lifestyle.Transient.CreateRegistration(type, container);
}
public override IEnumerable<Filter> GetFilters(
ControllerContext context,
ActionDescriptor descriptor)
{
var filters = base.GetFilters(context, descriptor).ToArray();
foreach (var filter in filters)
{
object instance = filter.Instance;
var registration = registrations.GetOrAdd(
instance.GetType(), this.registrationFactory);
registration.InitializeInstance(instance);
}
return filters;
}
}
您可以使用以下代码注册此自定义提供程序:
var filterProvider =
new SimpleInjectorFilterAttributeFilterProvider(container);
container.RegisterSingle<IFilterProvider>(filterProvider);
var providers = FilterProviders.Providers
.OfType<FilterAttributeFilterProvider>().ToList();
providers.ForEach(provider => FilterProviders.Providers.Remove(provider));
FilterProviders.Providers.Add(filterProvider);
此自定义SimpleInjectorFilterAttributeFilterProvider
调用Registration.InitializeInstance方法。此方法允许初始化已创建的类型,并将通过(除其他外)调用类型初始化器委托来初始化它。
有关使用属性的更多信息,请阅读以下讨论。