Pergunta

DTO

Estou construindo um aplicativo Web que gostaria de dimensionar para muitos usuários.Além disso, preciso expor a funcionalidade a terceiros confiáveis ​​por meio de serviços da Web.

Estou usando o LLBLGen para gerar a camada de acesso a dados (usando o SQL Server 2008).O objetivo é construir uma camada de lógica de negócios que proteja o Web App dos detalhes do DAL e, claro, fornecer um nível extra de validação além do DAL.Além disso, até onde posso dizer agora, o serviço da Web será essencialmente um invólucro fino sobre o BLL.

A DAL, é claro, possui seu próprio conjunto de objetos de entidade, por exemplo, CustomerEntity, ProductEntity e assim por diante.Porém, não quero que a camada de apresentação tenha acesso direto a esses objetos, pois eles contêm métodos específicos do DAL e o assembly é específico do DAL e assim por diante.Então, a ideia é criar Data Transfer Objects (DTO).A idéia é que estes sejam, essencialmente, objetos C#/.NET simples e antigos que possuem todos os campos de, digamos, um CustomerEntity que é na verdade a tabela de banco de dados Customer, mas nenhuma das outras coisas, exceto talvez algumas propriedades IsChanged/IsDirty.Então, haveria CustomerDTO, ProductDTO, etc.Presumo que estes seriam herdados de uma classe DTO base.Acredito que posso gerá-los com algum template para LLBLGen, mas ainda não tenho certeza.

Então, a ideia é que o BLL exponha sua funcionalidade aceitando e retornando esses objetos DTO.Acho que o serviço da Web cuidará da conversão desses objetos em XML para terceiros que o utilizam, muitos podem não estar usando .NET (além disso, algumas coisas poderão ser chamadas por script a partir de chamadas AJAX no aplicativo da Web, usando JSON).

Não tenho certeza da melhor maneira de projetar isso e exatamente como seguir em frente.Aqui estão alguns problemas:

1) Como isso deve ser exposto aos clientes (a camada de apresentação e o código do serviço Web)

Eu estava pensando que haveria uma classe pública que possui esses métodos, cada chamada seria uma operação atômica:

InsertDTO, UpdateDTO, DeleteDTO, GetProducts, GetProductByCustomer e assim por diante...

Então os clientes simplesmente chamariam esses métodos e passariam os argumentos apropriados, normalmente um DTO.

Esta é uma abordagem boa e viável?

2) O que retornar com esses métodos?Obviamente, o tipo de método Get/Fetch retornará DTO.Mas e as inserções?Parte da assinatura pode ser:

InsertDTO(DTO dto)

Porém, ao inserir o que deve ser retornado?Quero ser notificado sobre erros.No entanto, eu uso chaves primárias de incremento automático para algumas tabelas (no entanto, algumas tabelas possuem chaves naturais, principalmente as de muitos para muitos).

Uma opção que pensei foi uma classe Result:

class Result
{
    public Exception Error {get; set;}
    public DTO AffectedObject {get; set;}
}

Portanto, em uma inserção, o DTO obteria seu conjunto de propriedades get ID (como CustomerDTO.CustomerID) e, em seguida, colocaria esse objeto de resultado.O cliente saberá se há um erro se Result.Error! = null e então saberá o ID da propriedade Result.AffectedObject.

Será esta uma boa abordagem?Um problema é que parece que ele está passando muitos dados redundantes (quando é apenas o ID).Não acho que adicionar uma propriedade "int NewID" seria limpo porque algumas inserções não terão uma chave de incremento automático como essa.Outra questão é que não acho que os serviços da Web lidariam bem com isso.Acredito que eles retornariam apenas o DTO base para AffectedObject na classe Result, em vez do DTO derivado.Suponho que poderia resolver isso tendo MUITOS tipos diferentes de objetos Result (talvez derivados de um Result base e herdando a propriedade Error), mas isso não parece muito limpo.

Tudo bem, espero que isso não seja muito prolixo, mas quero ser claro.

Foi útil?

Solução

1:Essa é uma abordagem bastante padrão, que se adapta bem a uma implementação de "repositório" para a melhor abordagem testável por unidade.

2:Exceções (que devem ser declaradas como "falhas" no limite do WCF, aliás) serão geradas automaticamente.Você não precisa lidar com isso diretamente.Para dados – existem três abordagens comuns:

  • usar ref no contrato (não muito bonito)
  • retornar o objeto (atualizado) - ou seja, public DTO SomeOperation(DTO item);
  • retornar apenas as informações de identidade atualizadas (chave primária/timestamp/etc)

Uma coisa sobre tudo isso é que não é necessário um tipo diferente por operação (compare com seu Result classe, que precisaria ser duplicada por DTO).

Outras dicas

P1:Você pode pensar nos tipos compostos do contrato de dados do WCF como DTOs para resolver esse problema.Dessa forma, sua camada UI só tem acesso às propriedades DataMember do DataContract.Suas operações atômicas seriam os métodos expostos pela sua interface WCF.

Q2:Configure seus contratos de dados de resposta para retornar um novo tipo personalizado com suas chaves primárias, etc.O WCF também pode ser configurado para enviar exceções de volta para a interface do usuário.

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