2012-02-17 16 views
6

En mi aplicación mvc ASP.net estoy usando una capa de servicio y repositorios para mantener mis controladores delgados. A los detalles típicos de sólo lectura vista se ve así: CapaMVC - Comunicación de la controladora a la capa de servicio

public ActionResult Details(int id) 
{ 
    var project = _projectService.GetById(id); 

    return View(Mapper.Map<Project, ProjectDetails>(project)); 
} 

Servicio:

public class ProjectService : IProjectService 
{ 
    public Project GetById(int id) 
    { 
     var project = _projectRepository.GetProject(id); 

     // do some stuff 

     return project; 
    } 
} 

public class ProjectRepository : IProjectRepository 
{ 
    public Project GetProject(int id) 
    { 
     return context.Projects.Find(id); 
    } 
} 

Pasar de la capa de servicio al modelo de vista es bastante fácil debido a AutoMapper, que puede aplanar las cosas con bastante facilidad. Moviendo el otro directamente, desde el modelo de vista para pasar a mi capa de servicio es donde lucho para encontrar una buena solución.

En una situación como una acción Crear, ¿cuál es un buen enfoque para esto?

[HttpPost] 
public ActionResult Create(CreateProjectViewModel model) 
{ 
    if(!ModelState.IsValid) 
    { 
     return View(model); 
    } 

    // TODO 

    return RedirectToAction("Index"); 
} 

estoy bastante seguro de que la capa de servicio no debe saber nada acerca de modelos de vista, pero tampoco creo que AutoMapper funciona bien en este escenario tampoco, ya que no es bueno en tomar un modelo plano y convirtiéndolo en un objeto complejo.

¿Cómo debería mi controlador comunicarse con la capa de servicio? Quiero mantener el código en el controlador lo más ligero posible.

+1

Ya sabes, siempre he encontrado que AutoMapper es engorroso de esta manera, sería bueno si algo como Resharper pudiera implementar una forma de crear asignaciones en objetos complejos automáticamente. Podría hacer un buen complemento –

+0

Acerca de unflattening con AutoMapper: echó un vistazo a http://stackoverflow.com/questions/3145062/using-automapper-to-unflatten-a-dto? – rsenna

+0

@rsenna Voy a echar un vistazo a eso, gracias. – Dismissile

Respuesta

5

Se podría definir una asignación bidireccional y luego ir al revés:

[HttpPost] 
public ActionResult Create(CreateProjectViewModel model) 
{ 
    if(!ModelState.IsValid) 
    { 
     return View(model); 
    } 

    Project project = Mapper.Map<CreateProjectViewModel, Project>(model); 
    // pass the project entity to your service layer 
    _projectService.Create(project); 

    return RedirectToAction("Index"); 
} 

o si está actualizando una entidad probablemente lo primero que quieren buscar a la entidad existente que desea actualizar desde el servicio:

[HttpPost] 
public ActionResult Update(CreateProjectViewModel model) 
{ 
    if(!ModelState.IsValid) 
    { 
     return View(model); 
    } 

    Project project = _projectService.GetById(model.Id); 
    Mapper.Map<CreateProjectViewModel, Project>(model, project); 

    // pass the project entity to your service layer 
    _projectService.Update(project); 

    return RedirectToAction("Index"); 
} 
+1

Parece que a veces esto no funciona muy bien porque AutoMapper no puede pasar fácilmente de un modelo plano a un modelo complejo. – Dismissile

+1

@Dismissile, bueno, todo dependerá de cómo definas tu mapeo. Es cierto que es más fácil aplanar con AutoMapper, pero también podrías ir al revés y reconstruir el modelo de dominio original desde el modelo de vista. –

+0

cierto. ¿Es este el enfoque que usualmente tomas en tus proyectos? – Dismissile

1

La única manera que he visto este hecho hasta ahora es crear manualmente un montón de clases de transformación de modelos, por ejemplo:

public interface ITransformer<out To, in From> 
    where To : class 
{ 
    To Transform(From instance); 
} 

public class SomeDataToSomeViewModelTransformer : ITransformer<SomeViewModel, SomeDataModel> 
{ 
    public SomeViewModel Transform(SomeDataModel instance) 
    { 
     return new SomeViewModel 
      { 
       InvitationId = instance.Id, 
       Email = instance.EmailAddress, 
       GroupId = instance.Group.Id 
      }; 
    } 
} 

Y otra implementación de Transformer para volver al revés (ViewModel -> DataModel). Y que el controlador sepa que debe llamar al transformador correcto.

I +1 su pregunta porque me gustaría ver una buena y limpia manera de hacer esto también, sin tener que escribir manualmente un montón de código para mapear modelos.

+0

Creo que esto podría funcionar fácilmente. Sería fácil conectar los transformadores con el marco de Inyección de Dependencia. – Dismissile

0

Si su capa de servicio está exclusivamente dedicada a soportar su aplicación MVC y no a otros clientes, podría considerar el uso de los objetos pasados ​​y de su capa de servicio como parte de sus modelos de vista. Esto obviaría la necesidad de automatizar las llamadas entrantes, ya que enviaría los objetos reales requeridos desde el controlador.

También podría considerar no teniendo los servicios objetos de dominio de retorno, esto significaría que la automatización debe invocarse con los métodos de servicio en lugar de las acciones del controlador.

+0

La capa de servicio también es utilizada por una aplicación WCF, por lo que realmente no puede operar en los modelos de vista. – Dismissile

+0

Bastante justo. Mi enfoque no te queda bien. –

Cuestiones relacionadas