Pergunta

Na minha ASP.net MVC aplicativo que eu estou usando uma camada de serviço e Repositórios para manter meus controladores fina. Um detalhes típicos somente leitura view parece com isso:

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

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

Camada de Serviço:

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);
    }
}

Mover-se da camada de serviço para o modelo de vista é muito fácil por causa da AutoMapper, que pode achatar as coisas muito facilmente. Movendo o outro direto, a partir do modelo fim de passar para a minha camada de serviço é onde eu me esforço para chegar a uma boa solução.

Em uma situação como uma ação Criar, o que é uma boa abordagem para isso?

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

    // TODO

    return RedirectToAction("Index");
}

Eu tenho certeza que a camada de serviço não deve saber nada sobre modelos de exibição, mas eu também não acho que AutoMapper funciona bem neste cenário, quer, desde que não é bom em tomar um modelo de plano e tornando-se em um objeto complexo.

O que deve o meu olhar controlador de como se comunicar com a camada de serviço? Eu quero manter o código no controlador o mais leve possível.

Foi útil?

Solução

Você pode definir um mapeamento bidirecional e depois ir o contrário:

[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");
}

ou se você estiver atualizando uma entidade que você pode querer primeiro buscar a entidade existente que pretende actualizar a partir do serviço:

[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");
}

Outras dicas

A única maneira que eu já vi esse feito até agora é criar manualmente um grupo de classes de modelo de transformação, por exemplo:

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
            };
    }
}

E outra implementação Transformer para voltar para o outro lado (ViewModel -> DataModel). E ter o controlador sabe para chamar o transformador correto.

I +1 sua pergunta, porque eu adoraria ver uma maneira limpa agradável de fazer isso também, sem ter que escrever manualmente um monte de código para mapear modelos.

Se a sua camada de serviço é exclusivamente dedicado a apoiar a sua aplicação MVC e há outros clientes que você poderia considerar usando os objetos passaram e de sua camada de serviço como parte de seus viewmodels. Isto evitaria a necessidade de AUTOMAP as chamadas de entrada como você estaria enviando nos objetos reais necessários a partir do controlador.

Você também pode considerar não ter os serviços retornar objetos de domínio, isso significaria que o mapeamento automático deve ser invocado com os métodos do serviço, em vez das ações do controlador.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top