En ASP.NET MVC es muy utilizado (y también aconsejable) practicar el patrón ViewModel. Básicamente, el patrón ViewModel consiste en crear una clase específica para una vista con todo lo necesario para que pueda renderizarse. De este modo, evitamos el paso de información no estructura a la vista desde el controlador (como hacemos cuando utilizamos ViewBag).
En cualquier caso, el propósito de este post no es contar qué es un ViewModel sino que convenciones utilizo “yo” para su nombrado y ubicación dentro del código. Te prometo que cuando empiezas a tener muchos controladores, muchas acciones y muchos ViewModels, o te organizas o terminas con una maraña de clases importante (al menos a mí me pasa).
“Mis” convenciones son:
Crear una carpeta raíz en el proyecto con el nombre ViewModels.
Aquí a veces pienso en crear un ensamblado para guardar los ViewModels, pero bueno…
Dentro de esta carpeta, crear una nueva carpeta por cada controlador con el nombre del mismo. Por ejemplo y para el controlador Account: ViewModels\Account
Por cada método de acción de un controlador crear una clase con el nombre {Controller}{Action}ViewModel
¿Por qué pongo {Controller} en el nombre de la clase cuando ya está contenida en una carpeta (y por ende un espacio de nombres) también con {Controller}?
Pues lo hago porque me ayuda a reconocer mejor la clase fuera de ciertos contextos. Por ejemplo para un método de acción Index del controlador Customers, puedo llamar al ViewModel bien IndexViewModel o bien CustomersIndexViewModel. El problema de la segunda forma (la que utilizo) es que podría llegar a ser muy verbose... pero no me importa, con franqueza. Sin embargo, el problema de la primera forma (la que no incluye {Controller}) es que si la utilizo sin estar plenamente cualificada (esto es importando el espacio de nombres - using ViewModels.Customers), fuera del ámbito del controlador o su vista pierde significado y no puedo ubicarla directamente ni saber su propósito de un primer vistazo.
Otra convención (o convención sugerida, que no obligada, porque la cumplo cuando quiero y cuando no quiero no), es cambiar el nombre del ViewModel a {Controller}{View}ViewModel. Es decir, cambiamos {Action} por {View}. Esto lo hago porque no siempre la vista tiene el mismo nombre que la acción y entonces me parece que es justo que el nombre del ViewModel esté más cerca de a quién realmente pertenece, que es la vista y no a la acción.
Por último, si tengo dos ViewModels para la misma acción (normalmente una para la petición y otro para la respuesta), utilizo la palabra Request y Response para diferenciarlos (o también Get y Post) para diferenciarlos. Es decir, el nombre del ViewModel con este matiz queda así: {Controller}{Action}[Request|Response]ViewModel.
¿Y tus convenciones para ViewModel cuáles son?
¡¡Actualizado!!
Los buenos de @gulnor, @2Flores y @rf1souto me comentan otras opciones como la de crear una estructura basada en funcionalidades en vez de en la convención sugerida por MVC.
El post semilla de todo esto es Feature Folders in ASP.NET MVC. Para llevarlo a cabo (y agregando algo de nuestra propia cosecha) hemos hecho lo siguiente:
Agregar una nueva ruta donde buscar vistas al motor RazorViewEngine en el global.asax (este código no es el mejor, está claro, accede al motor por índice, pero ya se mejorará…). Lo importante es que preserva las rutas originales (las que siguen la convención de MVC) pero agregar una nueva:
var razorViewEngine = ViewEngines.Engines[1] as RazorViewEngine;var viewLocationFormats = razorViewEngine.ViewLocationFormats;var newViewLocationFormats = new List<string>(viewLocationFormats);newViewLocationFormats.Add("~/Features/{1}/Views/{0}.cshtml");razorViewEngine.ViewLocationFormats = newViewLocationFormats.ToArray();
Después simplemente crear una estructura de carpetas donde, como puedes ver, está agrupando por característica tanto el controlador como las vistas y ¿por qué no también los ViewModels?
El fichero Web.config lo hemos tenido que meter porque al principio nos daba un error la vista porque no heredaba de WebViewPage o WebViewPage<TModel>, pero rápidamente llegó stackoveflow al rescate y nos dio la idea.
Un saludo!