Por favor, disculpe la larga publicación. Hay una pregunta, solo tengan paciencia conmigo.
Un pequeño contexto
Tenemos un sitio que debe adaptarse considerablemente en función de una variedad de configuraciones de usuario, el grupo al que pertenece el usuario, de dónde provienen y otras cosas. Solíamos incluir los bits relevantes en el modelo para la página, por lo que si la página tenía una tabla que mostrara si el usuario era mayor de cierta edad, entonces en el modelo haríamos algo como:
//model
public PageModel
{
public bool ShowTable {get;set;}
}
//controller
public PageController
{
public ActionResult ShowPage()
{
var model = new PageModel() {
ShowTable = User.Age > 21
};
return View(model);
}
}
//view
@if(Model.ShowTable)
{
<table>Some Html here</table>
}
Esto rápidamente se volvió muy complicado para saber qué deberíamos mostrar a qué usuarios. Para tratar de abordar este problema, centralizamos toda la lógica sobre cuándo se debe mostrar u ocultar una cosa en particular. Llamamos a esta clase UserConfiguration
y (principalmente) solo contenía una serie de funciones que devuelven booleanos que indican lo que se debe mostrar. Esto nos permitió configurar una serie de especificaciones y pruebas de lo que debería mostrarse a un usuario. Esto UserConfigratuion
luego se puso en una clase base, de la cual todos los modelos de página debían heredar, por lo que actualmente tenemos algo como esto:
//UserConfiguration
public UserConfiguration
{
private readonly User _user;
public UserConfiguration(User user) {
_user = user
}
public bool ShowTable() {
return _user.Age > 21;
}
}
//model base
public ModelBase
{
public UserConfiguration {get;set;}
}
//model
public PageModel : ModelBase
{
// whatever data is needed for the page
}
//controller
public PageController
{
public ActionResult ShowPage()
{
var userConfiguration = new UserConfiguration(User);
var model = new PageModel {
UserConfiguration = userConfiguration
};
return View(model);
}
}
//view
@if(Model.UserConfiguration.ShowTable())
{
<table>Some Html here</table>
}
Esto ha ayudado, principalmente porque nos permitió crear una serie de pruebas de lo que un usuario debería y no debería ver, etc. Sin embargo, no es una solución muy limpia, tener que reunir esta clase adicional e incluirla en el modelo. También tiene ramificaciones para representar vistas parciales. Si el modelo tiene una propiedad IEnumerable<Foo> Foos
, que queremos representar en un parcial, pero ese parcial también se basa en la configuración del usuario, tenemos un problema. No puede simplemente pasar los foos a lo Parcial como modelo, porque entonces lo parcial no tiene acceso a lo parcial UserConfiguration
. Entonces, ¿cuál sería la mejor manera de acceder a esta información? A mi modo de ver, en el contexto de asp.net MVC hay 4 formas disponibles:
1) Tener un nuevo modelo para el parcial, por ejemplo
// parent view
@{
var foosModel = new foosModel {
Foos = Model.Foos,
UserConfiguration = Model.UserConfiguration
}
}
@Html.RenderPartial("FooList", foosModel)
// child partial view
@if(Model.UserConfiguration.ShowTable) {
foreach(var foo in Model.Foos) {
//Some HTML
}
}
Esta es probablemente la solución "más pura", que se adhiere mejor a los principios de MVC, pero involucra una gran cantidad de modelos (posiblemente innecesarios), lo que causa la hinchazón del proyecto.
2) Exponga la configuración del usuario a través de ViewData. p.ej :
// parent view
@Html.RenderPartial("FooList", Model.Foos, new ViewDataDictionary { { "UserConfiguration", Model.UserConfiguration } })
// child partial view
@{
var userConfig = (UserConfiguration)ViewData["UserConfiguration"];
}
@if(userConfig.ShowTable) {
foreach(var foo in Model) {
//Some HTML
}
}
Realmente no me gusta esto porque no es de tipo seguro y se basa en cadenas mágicas para obtenerlo de ViewData.
3) Coloque la configuración de usuario en la ViewBag. Los mismos problemas que los anteriores realmente
4) Modifique el modelo de página y exponga la configuración de usuario a través de una propiedad de la página en sí, según http://haacked.com/archive/2011/02/21/changing-base-type-of-a-razor-view .aspx /
Creo que dado que la configuración del usuario es información contextual ambiental, tiene sentido exponerla a través de la clase como en la opción 4 anterior. ¿Existe una práctica recomendada generalmente aceptada en MVC para exponer este tipo de datos? ¿Alguien ha intentado algo como la opción 4 en el pasado y hubo algún "problema"?
tl; dr: ¿Cuál es la mejor manera de exponer información contextual a las vistas en su sitio, en MVC en general o asp.net MVC en particular?
fuente