甚至可以将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()方法来设置依赖项解析器。

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

最佳答案

我想我终于解决了自己的问题。我不知道为什么验证提供程序现在可以正常工作,可能是由于更新了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()设置起点并根据需要对其进行修改。如果要在ValidatorProvider中使用对象,请随意存储从数据库检索的对象,以使用metadata.AdditionalValues确定MetaData。

10-02 02:38