Настройка DependancyResolver в MVC3 с использованием StructureMap для ModelMetadataProvider и ModelValidatorProvider - PullRequest
3 голосов
/ 30 марта 2011

Можно ли даже настроить MVC3 для использования DependencyResolver для получения пользовательского ModelMetadataProvider или ModelValidatorProvider?Потому что на данный момент я не могу заставить его работать так, как когда-либо через DependencyResolver.Если я устанавливаю это явно через код в global.asax, он работает отлично, но IoC просто молча игнорирует мой код.Я использую пакет StructureMap от NuGet, так что ничего особенного.

Мои текущие подключения через 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, у которого есть свойство Session, заполненное nHibernate.Я делаю это, потому что мне нужно определить, какие правила проверки определены в базе данных, исходя из проверяемого свойства.

Опять же, оба они работают.Но каждый раз, когда я пытаюсь настроить их, используя StructureMap, чтобы они были доступны для DependencyResolver, я не могу получить желаемый результат.Кто-нибудь еще делал это раньше и заставил его работать на самом деле полностью?Есть ли что-то необычное, что мне нужно сделать из-за параметров конструкторов?Существует ли определенный жизненный цикл, который должен быть установлен в регистрации StructureMap этих типов?Я искал везде примеры этого, но все они либо относятся к бета-версиям, либо к релизным кандидатам 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.

Вы можете видеть закомментированные строки, которые я пытался использовать для регистрации своих поставщиков метаданных и валидатора.Я не знаю, правильно ли я это делал или нет.Я добавил вызов для сканирования реестров, потому что у меня есть реестр для настройки и добавления nhibernate в контейнер Structuremap.

1 Ответ

1 голос
/ 30 марта 2011

Я думаю, что наконец-то решил свою проблему. Я не знаю, почему провайдер валидации работает сейчас, возможно, это было связано с изменением реализации метода GetServices () в файле SmDependencyResolver.cs, которое я заметил после обновления ссылки StructureMap.MVC3, я не 100% уверен.

Но у ModelMetaDataProvider возникла проблема. Пример, который я использовал из сети для реализации пользовательского ModelMetaDataProvider, был настроен в файле global.asax следующим образом.

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

Теперь это работает нормально, и оно запускается только один раз при запуске приложения. Но для реализации этого в IoC я думаю, что это вызывало проблему из-за ссылки ModelMetadataProviders.Current. Я не знаю, почему я никогда не получал ошибку, но по какой-то причине я изменил ее, чтобы создать новый экземпляр DataAnnotationsModelMetadataProvider(), и это, похоже, решило проблему. Моя регистрация пользовательского ModelMetadataProvider в карте структуры теперь выглядит следующим образом.

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

Надеюсь, это поможет любому, у кого может быть эта проблема.

ОБНОВЛЕНИЕ: Продолжение вопроса Рудиментера: У меня действительно были некоторые трудности с контролем жизни моего провайдера. Мой 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 только один раз запрашивает распознаватель зависимостей для реализации 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 на тот случай, если вы захотите использовать его и в ValidatorProvider.

...