Pergunta

Digamos que você tenha um projeto ASP.NET MVC e esteja usando uma camada de serviço, como neste tutorial do gerenciador de contatos no site asp.net: http://www.asp.net/mvc/tutorials/iteration-4-make-the-application-loosely-coupled-cs

Se você tiver viewmodels para suas visualizações, a camada de serviço é o local apropriado para fornecer cada viewmodel?Por exemplo, no exemplo de código da camada de serviço existe um método

    public IEnumerable<Contact> ListContacts()
    {
        return _repository.ListContacts();
    }

Se, em vez disso, você quisesse um IEnumerable, ele deveria ir para a camada de serviço ou existe algum outro lugar que seja o local "correto"?

Talvez mais apropriadamente, se você tiver um viewmodel separado para cada view associada ao ContactController, o ContactManagerService deveria ter um método separado para retornar cada viewmodel?Se a camada de serviço não for o local adequado, onde os objetos viewmodel devem ser inicializados para uso pelo controlador?

Foi útil?

Solução

Geralmente, não.

Os modelos de visualização destinam -se a fornecer informações para e de visualizações e devem ser específicos para o aplicativo, em oposição ao domínio geral. Os controladores devem orquestrar a interação com repositórios, serviços (estou fazendo algumas suposições da definição de serviço aqui), etc. e lidar com modelos de exibição e validação de exibição, além de conter a lógica de determinar as visualizações para renderizar.

Ao vazar modelos de visão em uma camada de "serviço", você está desfocando suas camadas e agora tem possíveis aplicativos e apresentação específicos misturados com o que deve focar com responsabilidades no nível do domínio.

Outras dicas

Não, eu não penso assim. Os serviços devem se preocupar apenas com o domínio do problema, não com a visão que torna os resultados. Os valores de retorno devem ser expressos em termos de objetos de domínio, não visualizações.

De acordo com a abordagem tradicional ou teoria, ViewModel deve fazer parte da camada de interface do usuário.Pelo menos o nome diz isso.

Mas quando você começa a implementá-lo sozinho com Entity Framework, MVC, Repositório etc., você percebe outra coisa.

Alguém precisa mapear modelos de entidade/banco de dados com ViewModels (DTO mencionado no final).Isso deve ser feito em [A] a camada UI (pelo Controlador) ou em [B] a camada de Serviço?

Eu vou com a opção B.A opção A é não, não devido ao simples fato de que vários modelos de entidade se combinam para formar um ViewModel.Não podemos passar dados desnecessários para a camada de UI, enquanto na opção B, o serviço pode brincar com os dados e passar apenas o necessário/mínimo para a camada de UI após o mapeamento (para o ViewModel).

Novamente, vamos com a opção A, colocar ViewModel na camada UI (e modelo de entidade na camada de serviço).

Se a camada de serviço precisar ser mapeada para o ViewModel, a camada de serviço precisará acessar o ViewModel na camada de UI.Qual biblioteca/projeto?O Viewmodel deve estar em um projeto separado na camada UI, e este projeto precisa ser referenciado pela camada de serviço.Se o ViewModel não estiver em um projeto separado, então há uma referência circular, então não vá.Parece estranho ter a camada de serviço acessando a camada UI, mas ainda assim conseguimos lidar com isso.

Mas e se houver outro aplicativo de UI usando este serviço?E se houver um aplicativo móvel?Quão diferente pode ser o ViewModel?O serviço deve acessar o mesmo projeto de modelo de visualização?Todos os projetos de UI acessarão o mesmo projeto ViewModel ou terão o seu próprio?

Após essas considerações minha resposta seria colocar o projeto Viewmodel na camada de serviço.Cada camada de UI precisa acessar a camada de serviço de qualquer maneira!E pode haver muitos ViewModels semelhantes que todos eles poderiam usar (portanto, o mapeamento se torna mais fácil para a camada de serviço).Atualmente, os mapeamentos são feitos através do linq, o que é outra vantagem.

Por último, há essa discussão sobre DTO.E também sobre anotação de dados em ViewModels.ViewModels com anotações de dados (Microsoft.Web.Mvc.DataAnnotations.dll) não podem residir na camada de serviço, em vez disso, residem na camada de UI (mas ComponentModel.DataAnnotations.dll pode residir na camada de serviço).Se todos os projetos estiverem em uma solução (.sln), não importa qual camada você coloca.Nas aplicações empresariais, cada camada terá sua própria solução.

Portanto, o DTO na verdade é um ViewModel porque principalmente haverá um mapeamento individual entre os dois (digamos, com o AutoMapper).Novamente, o DTO ainda possui a lógica necessária para a UI (ou vários aplicativos) e reside na camada de serviço.E o ViewModel da camada UI (se usarmos Microsoft.Web.Mvc.DataAnnotations.dll) serve apenas para copiar os dados do DTO, com alguns 'comportamentos'/atributos adicionados a ele.

[Agora esta discussão está prestes a tomar um rumo interessante, continue lendo...:I]

E não pense que os atributos de anotação de dados são apenas para UI.Se você limitar a validação usando o System.ComponentModel.dataannotações.dll, o mesmo viewmodel também poderá ser usado para validação front-end e back-end (removendo assim a UI-RESIDE-ViewModel-Copy-of-DTO).Além disso, atributos também podem ser usados ​​em modelos de entidades.Por exemplo:usando .tt, os modelos de dados do Entity Framework podem ser gerados automaticamente com atributos de validação para fazer algumas validações de banco de dados, como comprimento máximo, antes de enviar para o back-end.Outra vantagem é que, se a validação de back-end for alterada no banco de dados, o .tt (lê as especificações do banco de dados e cria o atributo para a classe de entidade) irá capturá-lo automaticamente.Isso também pode forçar a falha dos testes de unidade de validação da UI, o que é uma grande vantagem (para que possamos corrigi-lo e informar todas as UIs/consumidores em vez de esquecer e falhar acidentalmente).Sim, a discussão está a avançar no sentido de uma boa concepção do quadro.Como você pode ver, está tudo relacionado:validação em níveis, estratégia de teste de unidade, estratégia de cache, etc.

Embora não esteja diretamente relacionado à questão.'ViewModel Façade' mencionado neste item imperdível link do canal 9 também vale a pena explorar.Começa exatamente aos 11 minutos e 49 segundos do vídeo.Porque este seria o próximo passo/pensamento assim que sua pergunta atual acima for resolvida:'Como organizar ViewModels?'

Também no seu exemplo "_repository.ListContacts()" está retornando um ViewModel do repositório.Este não é um caminho maduro.Os repositórios devem fornecer modelos de entidade ou modelos de banco de dados.Isso é convertido em modelos de visualização e é esse modelo de visualização que é retornado pela camada de serviço.

Suponho que isso depende do que você considera os "serviços". Eu nunca gostei muito do termo serviço no contexto de uma única classe; É incrivelmente vago e não conta muito sobre o objetivo real da classe.

Se a "camada de serviço" for uma camada física, como um serviço da web, absolutamente não; Os serviços em um contexto de SOA devem expor operações de domínio/negócios, não dados e não lógica de apresentação. Mas se serviço está sendo usado apenas como um conceito abstrato para um nível adicional de encapsulamento, não vejo nenhum problema em usá -lo da maneira que você deseja.

Só não misture conceitos. Se o seu serviço lidar com os modelos de visualização, deve ser um Serviço de apresentação e ser em camadas sobre o topo do real Modelo, nunca tocando diretamente no banco de dados ou em qualquer lógica de negócios.

Isso chegou um pouco "depende" de onde eu trabalho - geralmente tivemos um controlador consumindo alguns serviços - então combinando os DTO retornados em um 'ViewModel' que então seria passado para o cliente - por meio de resultado JSON , ou amarrado no modelo de barbear.

A coisa é que cerca de 80% das vezes - o mapeamento do DTO para o ViewModel foi 1-1. Estamos começando a avançar em direção a 'onde necessário, basta consumir o DTO diretamente, mas quando o DTO e o que precisamos em nosso cliente/visualização não correspondem - então criamos um ViewModel e fazemos o mapeamento entre os objetos conforme necessário'.

Embora ainda não esteja convencido de que esta é a melhor ou a solução correta - pois acaba levando a algumas discussões acaloradas de 'estamos apenas adicionando X ao DTO para atender às necessidades da visão?'

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