如何在mvc3中使用Simple Injector注册自定义ModelMetadataProvider

jac*_*per 3 inversion-of-control asp.net-mvc-3 simple-injector

当我尝试使用简单的注入器注册模型元数据提供程序时,我没有收到任何错误,但是当我访问该实例时,默认情况下是mvc中的实例.

我试图注册简单注入器的方式是关注;

public static class SimpleInjectorInitializer{
    public static void Initialize(){
        var container = new Container(new ContainerOptions AllowOverridingRegistrations = true});
        InitializeContainer(container);
        container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
        container.RegisterMvcAttributeFilterProvider();
        container.Verify();
        DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
    }
    private static void InitializeContainer(Container container){   
        container.Register<ModelMetadataProvider, MyMetadataProvider>();
    }
Run Code Online (Sandbox Code Playgroud)

}

Ste*_*ven 7

如果我没弄错的话,您必须明确地向MVC注册您的自定义元数据提供程序:

ModelMetadataProviders.Current =
    new MyMetadataProvider();
Run Code Online (Sandbox Code Playgroud)

如果您还需要将此实例注入可从容器中解析的类型,则还需要在容器中注册它:

ModelMetadataProviders.Current =
    new MyMetadataProvider();

container.RegisterSingle<ModelMetadataProvider>(
    ModelMetadataProviders.Current);
Run Code Online (Sandbox Code Playgroud)

如果您希望容器将依赖项注入自定义MyMetadataProvider,则需要执行以下操作:

container.RegisterSingle<ModelMetadataProvider, MyMetadataProvider>();

container.Verify();

// Call this after you're done configuring the container.
ModelMetadataProviders.Current = 
   container.GetInstance<ModelMetadataProvider>();
Run Code Online (Sandbox Code Playgroud)

由于它ModelMetadataProviders.Current是一个单例,ModelMetadataProvider必须是单例,或者至少,它应该不是一个问题,它在应用程序的生命周期中被缓存并从多个线程同时访问.当您向其中注入依赖项时,这可能不适合您的自定义提供程序(因为这些依赖项的生命周期可能比单例生活方式更短).

在这种情况下,您应该创建一个回调到以下内容的代理提供程序DependencyResolver:

public DependencyResolverModelMetadataProvider : ModelMetadataProvider
{
    public override IEnumerable<ModelMetadata> GetMetadataForProperties(
        object container, Type containerType)
    {
        return GetProvider().GetMetadataForProperties(
            container, containerType);
    }

    public override ModelMetadata GetMetadataForProperty(
        Func<object> modelAccessor, Type containerType, string propertyName)
    {
        return GetProvider().GetMetadataForProperty(
            modelAccessor, containerType, propertyName);
    }

    public override ModelMetadata GetMetadataForType(
        Func<object> modelAccessor, Type modelType)
    {
        return GetProvider().GetMetadataForType(
            modelAccessor, modelType);
    }

    private static ModelMetadataProvider GetProvider()
    {
        return (ModelMetadataProvider)
            DependencyResolver.Current.GetService(
                typeof(ModelMetadataProvider));
    }
}
Run Code Online (Sandbox Code Playgroud)

由于此代理将调用DependencyResolver每次调用(并且不包含任何状态),因此您可以安全地创建单个实例并将其存储到ModelMetadataProviders.Current属性中.

在这种情况下,您的配置如下所示:

// register the proxy that calls back into the container.
ModelMetadataProviders.Current =
    new DependencyResolverModelMetadataProvider();

// Register it as transient.
container.Register<ModelMetadataProvider, MyMetadataProvider>();
Run Code Online (Sandbox Code Playgroud)

如果您希望自定义提供程序装饰原始提供程序,则需要将此原始提供程序注入自定义提供程序的属性(还有其他方法,但这是最简单的方法):

var original = ModelMetadataProviders.Current;

// register the proxy that calls back into the container.
ModelMetadataProviders.Current =
    new DependencyResolverModelMetadataProvider();

// Register it as transient.
container.Register<ModelMetadataProvider, MyMetadataProvider>();

container.RegisterInitializer<MyMetadataProvider>(prov =>
{
    // The decorated provider is put as a property on the
    // MyMetadataProvider class.
    prov.DecoratedProvider = original;
});
Run Code Online (Sandbox Code Playgroud)

另一种方法是将自定义注册MyMetadataProvider为装饰器类:

container.RegisterSingle<ModelMetadataProvider>(
    ModelMetadataProviders.Current);

container.RegisterDecorator(
    typeof(ModelMetadataProvider),
    typeof(MyMetadataProvider));

ModelMetadataProviders.Current =
    new DependencyResolverModelMetadataProvider();
Run Code Online (Sandbox Code Playgroud)

通过注册MyMetadataProvider为装饰器,它将被包裹在原始注册的ModelMetadataProvider(它将被注入到MyMetadataProvider.你需要SimpleInjector.Extensions.dll项目来获得RegisterDecorator扩展.