He estado tratando de encontrar una buena manera de manejar los modelos de nuestros sitios web Asp.net MVC cuando se tienen propiedades comunes para todas las páginas. Estas propiedades se mostrarán en el diseño (página maestra). Estoy usando una clase "BaseModel" que contiene esas propiedades y mi diseño utiliza este modelo base como modelo.Asp.net MVC Modelo para ver y diseño
Cada otro modelo hereda de ese BaseModel y cada uno tiene propiedades específicas relativas a la vista que representa. Como habrás adivinado, mis Modelos son en realidad Modelos de Vista, incluso si eso no es muy relevante aquí.
que han intentado diferentes maneras de inicializar los valores de la BaseModel
- Por "mano" en todas las vistas
- Tener un controlador de base que tiene un método virtual de inicialización para hacerlo (controlador de manera específica se puede poner en práctica específica comportamiento común para exemple)
- Tener una base controlelr que OnActionExecuting override para llamar al método de inicialización
- Uso de una clase de ayuda para hacerlo fuera del controlador
- utilizando un modelo de fábrica
Pero ninguno de los que realmente me atrae:
- me parece evidente, pero seco es una razón suficiente para justificar que (en realidad nunca he tratado de esa solución en absoluto, Solo lo estoy poniendo para poder repetir ese punto en el último punto).
- No me gusta porque significa que cada vez que se agrega un nuevo Controlador, necesita saber que tiene que heredarlo del BaseController y que necesita llamar al método Initialize, sin mencionar que si su controlador ha anulado la base, para llamar a la base de todos modos para mantener los valores.
- ver el siguiente punto
- y 3. son una variación del mismo tema, pero eso realmente no ayuda con los problemas de la segunda solución.
- Mi favorito hasta ahora, pero ahora tengo que pasar algunas variables más para establecer esos valores. Me gusta para la inversión de la dependencia. Pero si quiero proporcionar valores de la sesión, necesito pasarlos explícitamente, por ejemplo, luego vuelvo a la primera casilla, ya que tengo que proporcionarlos a mano (sean referencias o mediante una interfaz de cualquier tipo)
Por supuesto, (casi) todas esas soluciones funcionan, pero estoy buscando una mejor manera de hacerlo.
Al escribir esta pregunta, encontré tal vez una nueva ruta, la builder pattern que también podría funcionar, pero las implementaciones pueden convertirse rápidamente en una carga también, ya que podemos tener docenas de vistas y controladores.
Con gusto tomaré cualquier recomendación seria/pista/consejo/patrones/sugerencia!
actualización
Gracias a @EBarr me ocurrió otra solución, utilizando un ActionFilterAttribute (no código de producción, lo hicieron en 5 minutos):
public class ModelAttribute : ActionFilterAttribute
{
public Type ModelType { get; private set; }
public ModelAttribute(string typeName) : this(Type.GetType(typeName)) { }
public ModelAttribute(Type modelType)
{
if(modelType == null) { throw new ArgumentNullException("modelType"); }
ModelType = modelType;
if (!typeof(BaseModel).IsAssignableFrom(ModelType))
{
throw new ArgumentException("model type should inherit BaseModel");
}
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var model = ModelFactory.GetModel(ModelType);
var foo = filterContext.RequestContext.HttpContext.Session["foo"] as Foo;
model.Foo = foo;
model.Bar = somevalue;
filterContext.Controller.TempData["model"] = model;
}
}
llamando entonces es muy simple :
[Model(typeof(HomeModel))]
public ActionResult Index()
{
var homeModel = TempData["model"] as HomeModel;
// Add View Specific stuff
return View(homeModel);
}
Y me da lo mejor de todos los mundos. El único inconveniente es encontrar una forma adecuada de pasar el modelo a la acción.
Aquí se hace utilizando el objeto TempData, pero también considero actualizar el modelo que se puede encontrar en los ActionParameters.
Todavía estoy tomando cualquier recomendación seria/sugerencia/consejo/patrones/sugerencia para eso, o los puntos anteriores.
Gracias por su respuesta. Si bien no coincide exactamente con lo que estoy buscando (su solución es una implementación diferente de 3.), realmente me dio una idea. Solo traté de usar un ActionFilterAttribute personalizado que parece ser el truco. Todavía tengo que encontrar una forma "limpia" para devolverle el modelo a la acción (en este momento estoy usando TempData). Actualizaré la pregunta para reflejar eso. –
Sí, es una versión de # 3. Pensé en los atributos, pero eso requería decorar cada controlador/acción (según las necesidades). Mantenerlo en 'OnActionExecuting' y' OnActionExecuted' mantuvo mi código en un único controlador base. En la práctica para cualquier proyecto de MVC más grande, vas a tener un controlador base, así que no me importó mucho. También me permitió ejecutar la lógica en función del tipo de modelo, en lugar de vincular la lógica con la que se estaba ejecutando la acción. – EBarr
RE: Modelo de agarre: en su atributo de filtro de acción va a terminar implementando los mismos eventos (ejecución y ejecución), pero puede sacar el modelo de filterContext, no hay necesidad de devolverlo, simplemente búsquelo y llena lo que necesitas – EBarr