使用StructureMap for ModelMetadataProvider&amp ;;在MVC3中设置DependancyResolver。 ModelValidatorProvider

时间:2011-03-29 22:08:28

标签: asp.net-mvc-3 dependency-injection structuremap

是否可以设置MVC3以使用DependencyResolver来获取自定义的ModelMetadataProvider或ModelValidatorProvider?因为在这一点上我无法通过DependencyResolver让它工作。如果我通过global.asax中的代码显式设置它,它可以很好地工作,但IoC只是默默地忽略了我的代码。我正在使用NuGet的StructureMap包,所以它没什么特别的。

我目前通过global.asax连接 的global.asax.cs

ModelMetadataProviders.Current = new RedSandMetadataProvider(ModelMetadataProviders.Current);

ModelValidatorProviders.Providers.Add(new RedSandValidatorProvider((IUnitOfWork)DependencyResolver.Current.GetService(typeof (IUnitOfWork))));

这些都很完美。 我必须将当前的ModelMetaDataProvider作为构造函数传递给我的自定义函数,因为您一次只能连接一个ModelMetaDataProvider。所以我通过检查方法参数处理我需要的调用,然后让其余的调用到基础实现。

我的ModelValidatorProviders使用IUnitOfWork对象,该对象具有由nHibernate填充的Session属性。我这样做是因为我需要根据要验证的属性确定数据库中定义的验证规则。

同样,这两者都有效。但每次我尝试使用StructureMap设置它们以便它们可用于DependencyResolver我无法获得所需的结果。有没有其他人之前完成过这项工作并让它完全正常工作?由于构造函数上的参数,我需要做些什么吗?是否有一个特定的生命周期必须在StructureMap的这些类型的注册中设置?我已经看过无处不在的这方面的例子,但他们都指的是beta版或发布不适用于最终版本的MVC3的候选人,或者是那些说它可能但不是'的文章实际上用一个例子证明了它。

我真的很感谢任何人对此的帮助,因为我正在努力解决这个问题应该是多么简单,网上的所有资源都是可能的,但我不能复制他们的任何生活。权利要求中。

更新

我使用的是StructureMap.MVC3 1.0.5,我注意到有更新后我刚刚更新到1.0.6,但版本之间似乎没有太大区别?

我的StructureMap设置

public static IContainer Initialize() {
    ObjectFactory.Initialize(x =>
                {
                    x.Scan(scan =>
                        {
                                //scan.AssembliesFromApplicationBaseDirectory(); //Would this let us setup dependancy injection to dynamically load plugins?
                                scan.TheCallingAssembly();
                                scan.WithDefaultConventions();
                                scan.LookForRegistries();
                            });
                    //x.For<IExample>().Use<Example>();

                    //x.For<ITempDataProvider>().Use( new CookieTempDataProvider(HttpContext.Current.Request.RequestContext.HttpContext));
                    //x.For<ModelMetadataProvider>().Singleton().Use(new RedSandMetadataProvider(ModelMetadataProviders.Current));
                    //x.For<ModelValidatorProvider>().Use<RedSandValidatorProvider>();
                });
    return ObjectFactory.Container;
}

我已经让使用WebActivator的包添加的Start()方法设置了Dependency Resolver。

您可以看到我尝试用于注册我的元数据和验证器提供程序的行已注释掉。我不知道我这样做的方式是否正确。我添加了扫描注册表的调用,因为我有一个Registry来配置并添加nhibernate到structuremap的容器。

1 个答案:

答案 0 :(得分:1)

我想我最终解决了自己的问题。我不知道为什么验证提供程序现在可以工作,这可能是由于更改了StructureMap.MVC3引用后我注意到的SmDependencyResolver.cs文件中GetServices()方法的实现发生了变化,我不是100%肯定。

但ModelMetaDataProvider确实遇到了问题。我在网上用来实现自定义ModelMetaDataProvider的例子让它在global.asax文件中设置如此。

ModelMetadataProviders.Current = new RedSandMetadataProvider(ModelMetadataProviders.Current);

现在这个工作正常,只有在应用程序启动时才会点击一次。但是为了在IoC中实现它,我认为由于ModelMetadataProviders.Current引用而导致问题。我不知道为什么我从来没有得到过错误,但我一时兴起将其更改为实例化一个新的DataAnnotationsModelMetadataProvider()实例,这似乎解决了这个问题。 我在结构图中注册自定义ModelMetadataProvider现在就是这样。

x.For<ModelMetadataProvider>().Use(new RedSandMetadataProvider(new DataAnnotationsModelMetadataProvider()));

我希望这可以帮助其他可能遇到此问题的人。

更新:跟进Rudimenter的问题: 实际上我在控制提供商的生命周期方面也遇到了一些困难。我的ModelMetaDataprovider从数据库中提取信息以确定我将传回的模型元数据,但由于MVC控制ModelMetadataProvider的方式,我的数据源的生命周期与提供者的生命周期不同步。最后,我承认我采取了懒惰的方式,并在我的提供程序中创建了一个私有属性,返回我的数据源,其生命周期由DependancyResolver控制。如果有人有任何建议,我愿意接受替代方案,但当时这是对我有用的解决方案。

    private IMyMetadataRepository metadataRepository;
    private IMyMetadataRepository MetadataRepository
    {
        get
        {
            if (metadataRepository == null || !metadataRepository.IsConnected)
                this.metadataRepository = (IMyMetadataRepository)DependencyResolver.Current.GetService(typeof(IMyMetadataRepository));
            return metadataRepository;
        }
    }

更新:显然这些问题一直在增加流量,所以我想我会更新我的答案。根据其他人的评论,MVC仅查询Dependency解析器一次,以实现ModelMetadataProvider。我在维护数据库存储库的生命周期时遇到了其他问题。我已经将代码更改为如下,并且从那时起就没有任何问题。

public class RedSandMetadataProvider : DataAnnotationsModelMetadataProvider
{
    private IRepository<PseudoObjectStructure> StructureRepository
    {
        get
        {
            return (IRepository<IMyMetadataRepository>)DependencyResolver.Current.GetService(typeof(IRepository<IMyMetadataRepository>));
        }
    }

    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        ModelMetadata metadata = null;
        //logic for populating metadata here
        return metadata;
    }
}

我建议您使用new ModelMetadata()设置起点并根据需要进行修改。您可以随意存储从数据库中检索的对象,以确定使用metadata.AdditionalValues时的MetaData,以防您想在ValidatorProvider中使用它。