separate net mvc framework asp c# asp.net-mvc model-view-controller refactoring asp.net-mvc-viewmodel

c# - net - ¿Cómo puedo refactorizar el código de acceso a mi base de datos fuera de mi proyecto MVC pero mantener mis modelos de vista adentro?



view model mvc c# (5)

En general, utilizo la siguiente configuración / arquitectura al diseñar una aplicación MVC en la que necesito reutilizar los modelos:

Proyecto MVC: todo lo relacionado con la web. Defino ViewModels aquí y los mapeo a los modelos de dominio.

Proyecto de Modelos: biblioteca de clases con toda la lógica de tu dominio.

Proyecto de repositorio: esta es una biblioteca de clases que accede a la base de datos y los modelos de dominio.

La forma en que funciona es que el proyecto MVC usará la biblioteca de repositorio (con suerte inyectada) para obtener el modelo de dominio y asignarlo a su propio ViewModel.

Si también desea separar la asignación, puede colocar la capa de asignación, como han sugerido otros (utilizando eventualmente AutoMapper), en un proyecto separado. La capa de asignación hará referencia a los repositorios (y los modelos de dominio), mientras que la aplicación MVC solo hará referencia a la capa de asignación.

El problema es que la capa de mapeo, al crear ViewModels, necesitará una referencia a System.Web.Mvc como lo descubrió y no puede escapar de esto. Es por eso que otros han dicho, y estoy de acuerdo, que debe tener una capa de mapeo por proyecto.

Una buena manera de evitar esto es tener una capa de mapeo genérica adicional con clases de mapeo definidas para los casos comunes (como el correo electrónico). Luego, en las clases secundarias específicas, puede definir la asignación para casos específicos (como los que dependen de System.Web.Mvc).

Así que la pila final sería algo como lo siguiente, las dependencias bajando. Por supuesto, todo debe estar basado en la interfaz.

MVC App Console App | | | | MVC Specific Mapper Console Specific Mapper / / / / / / GenericMapper <- EmailMapper and EmailViewModel can be implemented here | | | | Repository | | | | | DomainModels

Lo anterior no es una lucha libre y probablemente el esfuerzo de dividir el mapeo no valga la pena si solo hay uno o dos casos comunes. De esa manera, desde el Mapeador genérico hacia abajo, usted está libre de la biblioteca System.Web.Mvc, mientras que por encima de usted es libre de olvidar el código de acceso a la base de datos (en cierto sentido, el Mapeador actuará como un repositorio para la aplicación).

Tengo un sitio web asp.net-mvc con las siguientes carpetas:

  • Controladores
  • Guiones
  • Puntos de vista
  • ViewModels
  • Modelos
  • DomainModel

Ahora quiero acceder a una gran cantidad de esta lógica de negocios y código de acceso a la base de datos y datos en otra aplicación .net (una aplicación de consola de Windows, por lo tanto no es web), así que estoy refactorizando para eliminar tantas cosas como sea posible fuera del proyecto MVC y en otros proyectos en la solución para que el código pueda compartirse con estas otras soluciones.

Tengo 2 problemas principales;

  1. Mi principal problema es que estoy luchando para encontrar un lugar para colocar el código que genera el ViewModel porque gran parte de este código me gustaría reutilizarlo en la aplicación de la consola, ya que la aplicación de la consola envía un correo electrónico que requiere los mismos datos que se encuentran en el ver.

  2. Otro problema principal es que estoy luchando para ver cómo puedo mover el código de acceso a mi base de datos fuera del proyecto MVC mientras sigo teniendo ViewModels dentro, cuando muchas de mis funciones que crean instancias de mis modelos de vista comienzan con un montón de código de acceso a la base de datos.

Aquí está un poco de los detalles y mi proceso hasta ahora:

Paso 1 - Mueva DomainModel a otro proyecto - éxito

Así que mover el proyecto DomainModel fue simple (ya que era una gran cantidad de objetos en bruto con algo de lógica de negocios en la parte superior, nada de eso en la web).

Paso 2 - Controladores delgados - éxito

He diluido la mayor cantidad posible de mis controladores y moví cualquier lógica de negocios o lógica de acceso a datos complicada a la carpeta Modelos. Cuando intenté mover la carpeta de modelos fuera del proyecto MVC, se rompieron algunas cosas:

Paso 3 - Intenta mover la carpeta de Modelos fuera del Proyecto MVC - fight

Al adelgazar los controladores, tengo una serie de acciones de controlador diferentes que van a una clase de modelo y devuelven mi ViewModel que devuelvo a la vista. Algo como esto (en mi clase de controlador):

public ActionResult ApplicationDetail(int id) { AppDetailViewModel applicationViewModel = Model.GenerateAppDetailViewModel(id); return View(applicationViewModel); }

Así que los archivos en mi carpeta de Modelo son dependientes de las clases de ViewModel. Quiero centralizar la función GenerateAppDetailViewModel () ya que se utiliza en varios controladores diferentes. Además, en la aplicación de mi consola (que envía un correo electrónico, a menudo quiero obtener todos los datos que están en alguna vista, por lo que mi código "quiere" también para aprovechar el viewmodel ... si lo saco del proyecto MVC luego puedo reutilizarlo pero creo que tengo el problema de dependencia (claramente no necesito SelectListItem en la aplicación de mi consola, pero en otros casos donde son solo objetos de contenedor de datos diferentes necesarios para generar una vista que quiero reutilizar)

u otra cosa que se rompió fue la dependencia de:

System.Web.Mvc

Porque tengo mucho código que:

  1. consulta una tabla en una base de datos
  2. Convierte eso en una colección de objetos (estoy usando nhibernate)
  3. Conviértalo en un objeto DTO (que se encuentra en la carpeta ViewModels) o en una lista de objetos SelectListItem (que se utilizará para rellenar los desplegables en la vista) que forma parte de System.web.mvc.

Quería buscar sugerencias sobre la mejor manera de romper esta dependencia para poder mover la mayor cantidad posible de código del proyecto MVC para su reutilización.

El problema es que si intento chupar mi código de ViewModel en la carpeta del Modelo y en otro proyecto, de nuevo me quedo atascado porque las clases de ViewModel tienen mucha dependencia de

System.Web.Mvc

Debido a cosas como SelectListItem.

¿Debo tener 2 carpetas de modelos de visualización (una en el proyecto MVC que tiene referencias específicas a system.web.mvc y otra que se encuentra en un proyecto diferente?). Parece que la dependencia en SelectListItem es lo que sigue causando la contención

En la mayoría de los ejemplos que he visto, ViewModels tiene una dependencia en System.Web.Mvc como este tutorial

He visto estas preguntas:

que están relacionados pero no estoy seguro de que respondan a mi pregunta específica de refactorización general planteada.


Entiendo lo que quiere lograr, y debo decirle: es absolutamente normal reutilizar los mismos ViewModels para diferentes capas de IU. Después de todo, la VM es parte del patrón MVVM, y ese patrón se trata de separar las preocupaciones. Y, la separación significa la capacidad de reemplazar las capas de nivel inferior con otras implementaciones. Ese es el propósito de capas de software separadas (entre otras).

  1. Para comenzar, debe asumir que su proyecto web MVC está basado en MVVM. Eso te ayudará mentalmente a tomar decisiones correctas. Supongo que ya hiciste esto ya que ViewModel término ViewModel .
  2. Haz que ViewModels se convierta en plataforma independiente. Es posible, y no tiene nada que ver con SelectListItem . Después de todo, SelectListItem simplemente contiene la opción de par de texto / valor, más la bandera, ya sea que esté seleccionada o no. Obviamente puedes expresar la misma información de una manera diferente. Después de pasar este tipo genérico de ViewModel al MVC, puede convertir el genérico "SelectListItem" al MVC SelectListItem . Sí, es una especie de mapeo, y no importa si tiene lugar en la vista MVC o antes de pasarlo a la Vista. Pero debe suceder en la capa UI (proyecto web MVC), ya que se trata de un problema de mapeo específico de la plataforma.
  3. Usted mencionó el código de acceso a datos: es una capa de software separada, generalmente inyectada de forma abstracta en los modelos de visualización. No preveo problemas con esta parte.

Por lo tanto, terminará teniendo diferentes capas de software (probablemente en diferentes bibliotecas .NET): Capa de acceso a datos, capa de ViewModel, capa web MVC.

Existe la posibilidad de que también se haya definido MVC ViewModels (uno que pasó de Controlador a Ver) en el proyecto MVC, pero esos serán simplemente el manejo (probablemente aceptando) los ViewModels genéricos y la exposición de los términos en los términos específicos de MVC View (mapeo, Herencia, tu imaginación?). Y esto también es normal: después de todo, MVC es una interfaz de usuario basada en web y definitivamente tiene diferencias específicas de plataforma que deben manejarse a nivel de plataforma, no antes. El ViewModel específico de MVC sería un buen lugar para manejar la asignación de genérico a SelectListItem MVC.

Una vez que se realiza esta refactorización, no hay nada que le impida implementar otra aplicación de consola de capa de UI que esté mencionando, utilizando los mismos ViewModels genéricos que la otra capa de UI: el proyecto web MVC. Al usar los ViewModels genéricos en la aplicación de la consola, si se enfrenta a los problemas específicos de la plataforma de la Consola, puede crear los ViewModels específicos de la plataforma de la misma manera que expliqué anteriormente para los ViewModels específicos de MVC.


Los modelos de vista son específicos de la aplicación particular. Supongo que los modelos de vista diferirían entre su aplicación web y su aplicación de consola. Por lo tanto, cada aplicación debe definir sus propios modelos de vista y la asignación correspondiente entre los modelos de dominio y los modelos de vista. No tenga los modelos de dominio que poseen métodos que los conviertan en modelos de vista, ya que de esta manera está vinculando completamente su capa de dominio a la capa de UI, lo que es lo peor que puede pasar. Utilice una capa de mapeo (que será específica para cada tipo de aplicación). AutoMapper es un gran ejemplo de una capa de mapeo que podrías tener.

Ni siquiera intente reutilizar los modelos de vista MVC de ASP.NET en una aplicación de consola. Como ya ha descubierto, contendrán referencias a System.Web.Mvc porque, por ejemplo, un dropDownList en ASP.NET MVC se representa con la IEnumerable<SelectListItem> mientras que en una aplicación de consola, Dios sabe, tal vez un IEnumerable<SomeItemViewModel> .

Conclusión: los modelos de vista y la asignación entre el dominio y los modelos de vista pertenecen a la capa UI (también conocido como ASP.NET MVC, Console, WPF, ...).


Puede crear modelos de vista en el controlador con métodos de extensión:

Controlador:

public ActionResult ApplicationDetail(int id) { var model = _serviceLayer.GetSomeModel(id); var viewModel = model.CreateInstance(model); return View(viewModel); }

Crea estas SomeModelExtensions de SomeModelExtensions en tu proyecto SomeModelExtensions

public class SomeModelExtensions { public AppDetailViewModel CreateInstance(this SomeModel model) { var viewModel = new AppDetailViewModel(); // here you create viewmodel object from model with logic return viewModel; } }


Supongo que la web de MVC usará los mismos datos que la aplicación de la consola + campos adicionales, ¿verdad?

Entonces, ¿qué pasa con la herencia de su ViewModel del modelo? De esa manera, podrá reutilizar el modelo y obtener campos personalizados en su ViewModel según sea necesario.

public class AppDetailModel { public int ID { get; set; } public string Name { get; set; } } public class AppDetailViewModel : AppDetailModel { public string ViewProperty { get; set; } }