3

当我尝试使用简单的注入器注册模型元数据提供程序时,我没有收到任何错误,但是当我访问实例时,默认情况下是 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>();
    }

}

4

1 回答 1

7

如果我没记错的话,您必须将您的自定义元数据提供程序显式注册到 MVC:

ModelMetadataProviders.Current =
    new MyMetadataProvider();

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

ModelMetadataProviders.Current =
    new MyMetadataProvider();

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

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

container.RegisterSingle<ModelMetadataProvider, MyMetadataProvider>();

container.Verify();

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

由于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));
    }
}

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

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

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

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

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

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;
});

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

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

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

ModelMetadataProviders.Current =
    new DependencyResolverModelMetadataProvider();

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

于 2012-08-15T07:23:50.927 回答