asp.net mvc 3 - ventajas - Configurando DependancyResolver en MVC3 usando StructureMap para ModelMetadataProvider y ModelValidatorProvider
razor mvc (1)
¿Es posible incluso configurar MVC3 para usar DependencyResolver para obtener un ModelMetadataProvider o ModelValidatorProvider personalizado? Porque en este momento no puedo hacer que funcione a través de DependencyResolver. Si lo configuro explícitamente a través de un código en el archivo global.asax, funciona perfectamente, pero el IoC simplemente ignora silenciosamente mi código. Estoy usando el paquete StructureMap de NuGet, así que no es nada sofisticado.
Mis conexiones actuales a través de global.asax Global.asax.cs
ModelMetadataProviders.Current = new RedSandMetadataProvider(ModelMetadataProviders.Current);
ModelValidatorProviders.Providers.Add(new RedSandValidatorProvider((IUnitOfWork)DependencyResolver.Current.GetService(typeof (IUnitOfWork))));
Estos funcionan perfectamente. Tengo que pasar el ModelMetaDataProvider actual como un constructor a uno personalizado porque solo puedes tener un ModelMetaDataProvider conectado a la vez. De modo que manejo las llamadas que necesito inspeccionando los parámetros del método y dejo que el resto caiga en la implementación básica.
My ModelValidatorProviders utiliza un objeto IUnitOfWork que tiene una propiedad de sesión poblada por nHibernate. Lo hago porque necesito determinar qué reglas de validación están definidas en la base de datos a partir de la propiedad que se valida.
Nuevamente, estos dos funcionan. Pero cada vez que intento configurarlos con StructureMap para que estén disponibles para DependencyResolver, no puedo obtener el resultado deseado. ¿Alguien más ha hecho esto antes y lo ha conseguido realmente funcionar completamente? ¿Hay algo sofisticado que deba hacer debido a los parámetros en los constructores? ¿Hay un ciclo de vida específico que debe establecerse en el registro de estos tipos de StructureMap? He buscado ejemplos de esto en todas partes, pero todos se están refiriendo a versiones beta o candidatos de lanzamiento de MVC3 que no se aplican a la versión final, o son artículos que dicen que es posible pero en realidad no lo prueban con un ejemplo .
REALMENTE agradecería la ayuda de cualquier persona con esto porque me estoy volviendo loco sobre lo simple que debe ser, que todos los recursos en la red DICEN que es posible, pero no puedo por la vida de replicar ninguno de sus reclamos.
Actualizar
Estaba usando StructureMap.MVC3 1.0.5, recién actualicé a 1.0.6 luego de notar que había una actualización, sin embargo, no parece haber mucha diferencia entre las versiones?
Mi configuración de 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;
}
He dejado que Dependency Resolver se configure con el método Start () agregado por el paquete usando WebActivator.
Puede ver las líneas que estaba tratando de usar para registrar mis metadatos y validar a los proveedores. No sé si la forma en que lo estaba haciendo era correcta o no. Agregué la llamada para buscar registros porque tengo un Registro para configurar y agregar nhibernate al contenedor de StructureMap.
Creo que FINALMENTE he resuelto mi problema. No sé por qué el proveedor de validación funciona ahora, puede haber sido debido al cambio en la implementación del método GetServices () en el archivo SmDependencyResolver.cs que noté después de actualizar la referencia StructureMap.MVC3, no estoy 100% seguro.
Pero el ModelMetaDataProvider tuvo un problema. El ejemplo que estaba usando desde la red para implementar un ModelMetaDataProvider personalizado lo configuró en el archivo global.asax como tal.
ModelMetadataProviders.Current = new RedSandMetadataProvider(ModelMetadataProviders.Current);
Ahora esto funciona bien, y solo se golpea una vez cuando se inicia la aplicación. Pero para implementarlo en IoC, creo que estaba causando un problema debido a la referencia de ModelMetadataProviders.Current
. No sé por qué nunca recibí un error, pero por capricho lo cambié para instanciar una nueva instancia de DataAnnotationsModelMetadataProvider()
y eso pareció resolver el problema. Mi registro del ModelMetadataProvider personalizado en el mapa de estructura se ve así ahora.
x.For<ModelMetadataProvider>().Use(new RedSandMetadataProvider(new DataAnnotationsModelMetadataProvider()));
Espero que esto ayude a cualquier otra persona que pueda haber tenido este problema.
ACTUALIZACIÓN: seguimiento a la pregunta de Rudimenter: en realidad tuve algunas dificultades para controlar la vida de mi proveedor también. Mi ModelMetaDataprovider está extrayendo información de una base de datos para determinar los metadatos del modelo que pasaría, pero debido a la forma en que MVC controla ModelMetadataProvider, la vida útil de mi fuente de datos no estaba sincronizada con la duración del proveedor. Al final, admito que tomé la forma perezosa y creé una propiedad privada en mi proveedor que devolvía mi fuente de datos con su tiempo de vida controlado por DependancyResolver. Si alguien tiene alguna sugerencia, estoy abierto a las alternativas, pero en el momento esta fue la solución que funcionó para mí.
private IMyMetadataRepository metadataRepository;
private IMyMetadataRepository MetadataRepository
{
get
{
if (metadataRepository == null || !metadataRepository.IsConnected)
this.metadataRepository = (IMyMetadataRepository)DependencyResolver.Current.GetService(typeof(IMyMetadataRepository));
return metadataRepository;
}
}
ACTUALIZACIÓN: Al parecer, esta pregunta sigue recibiendo tráfico, así que pensé en actualizar mi respuesta. Según los comentarios de otros, MVC solo consulta el resolutor de Dependencia una vez para una implementación de ModelMetadataProvider. Y encontré otros problemas para mantener la vida útil de mi repositorio de base de datos. Desde entonces he cambiado el código para que sea el siguiente y no he tenido ningún problema con respecto a esto desde entonces.
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;
}
}
Te recomiendo que uses los new ModelMetadata()
para configurar tu punto de partida y modificarlo según sea necesario. Siéntase libre de almacenar el objeto que recupera de la base de datos para determinar el MetaData en el uso de metadata.AdditionalValues
en caso de que quiera usarlo en un ValidatorProvider también.