Expondo Tipos POCO através do WCF

by Israel Aece 4. July 2011 23:02

Ao construir serviços WCF, podemos expor tipos que vão além dos tipos tradicionais (tais como strings, inteiros, etc.), ou seja, podemos recorrer a construção de tipos customizados, onde construimos classes com suas propriedades que determinam os dados que serão carregados entre o cliente e o serviço.

Algumas vezes essas classes são construídas com o intuito de atender a requisição e/ou resposta das operações de um determinado serviço, mas que internamente, são consultas que fazemos no banco de dados e estamos retornando ao cliente, ou ainda, são comandos que devemos executar, também no banco de dados, para persitir alguma informação.

Se optarmos pelo uso do Entity Framework, podemos utilizar o modelo de geração POCO, onde as classes geradas são consideradas "puras", ou seja, não dependem de nenhuma classe do framework de persistência. Isso tornam as classes simples, apenas com as propriedades que são, em princípio, mapeadas para colunas da base de dados. Sendo assim, muitos podem optar pela exposição direta destas classes no contrato de um serviço WCF, evitando assim a criação de outras classes (DTOs) para efetuar o transporte das informações.

Mas expor diretamente essas classes podem acarretar alguns problemas. A questão é que entidades que foram geradas utilizando o modelo POCO, possuem um comportamento durante a execução diferente das entidades que são geradas pelo modelo padrão do Entity Framework. Quando utilizamos o modelo padrão, as entidades herdam diretamente da classe EntityObject, que fornece toda a infraestrutura necessária para efetuar o rastreamento das mudanças e dá também o suporte ao lazy-loading. Quando utilizamos classes POCO, esses recursos continuam sendo oferecidos, mas são implementados de forma diferente.

Neste caso, o Entity Framework gera proxies dinâmicos para interceptar os acessos às propriedades das entidades que estão sendo manipuladas, e com isso, todos os recursos acima, continuam ainda sendo suportados. Abaixo temos o objeto Type da classe que foi gerada dinamicamente.

{System.Data.Entity.DynamicProxies.Cliente_B38C1C71074F1A0CDCF11548021F55AF4BAC2116057847A45ACD8E600D02BB90}

Só que ao expor esse tipo de objeto diretamente através do WCF, vamos nos deparar com uma exceção durante a execução. Isso se deve ao fato de que o WCF não é capaz serializar/deseralizar tipos que não são conhecidos pelo mesmo. Ao construir o contrato para um serviço WCF, você pode mencionar os tipos das classes geradas efetivamente pelo EDMX, mas durante a execução, o tipo acima será criado e, consequentemente, será entregue para a infraestrutura do WCF, ele irá se certificar de que o tipo é conhecido no contrato, e como não é, a exceção será disparada.

Há algumas alternativas para evitar esse problema. A primeira delas é desabilitar a criação do proxy dinâmico através da propriedade boleana ProxyCreationEnabled, que está acessível através do contexto do Entity Framework, assim como é exibido no código abaixo. O problema é que ao fazer isso, entidades criadas no padrão POCO não serão capazes de fornecer as funcionalidades de rastreamento de mudanças e lazy-loading.

public class Servico : IContrato
{
    public Cliente Recuperar(int id)
    {
        using (DBTestesEntities1 ctx = new DBTestesEntities1())
        {
            ctx.ContextOptions.ProxyCreationEnabled = false;

            return (from c in ctx.Cliente where c.ClienteId == id select c).Single();
        }
    }
}

A outra opção é a criação de um behavior que pode ser aplicado em nível de operação, alterando o serializador padrão do WCF, que é o DataContractSerializer, para o serializador ProxyDataContractResolver. Este serializador, que está debaixo do namespace System.Data.Objects, ajuda na resolução dos tipos que são criados dinamicamente pelo Entity Framework em "tipos concretos", recorrendo ao método estático GetObjectType, exposto através da classe ObjectContext, que dado o Type do proxy dinâmico, ele retorna o tipo correspondente POCO, informando ao WCF que Type correto para que ele possa ser capaz de serializá-lo. Abaixo temos um exemplo da implementação e aplicação deste behavior:

public class ProxyDataResolverAttribute : Attribute, IOperationBehavior
{
    public void ApplyDispatchBehavior(OperationDescription opDescription, DispatchOperation dop)
    {
        opDescription
            .Behaviors
            .Find<DataContractSerializerOperationBehavior>()
            .DataContractResolver = new ProxyDataContractResolver();
    }

    //outros métodos
}

[ServiceContract]
public interface IContrato
{
    [OperationContract]
    [ProxyDataResolver]
    Cliente Recuperar(int id);
}

E, finalmente, uma terceira opção, seria a utilização de DTOs (Data Transfer Objects), onde você pode definir os objetos que quer trafegar entre as partes, sem a necessidade de se preocupar com detalhes de uma tecnologia específica que esteja utilizando nos bastidores e, principalmente, de ter a possibilidade de desacoplar complementamente o que representa os seus dados/domínio daquilo que quer expor para os clientes/parceiros.

Tags: , , ,

Data | WCF

Evento de Tecnologia em Hortolândia

by Israel Aece 25. May 2010 21:36

No próximo dia 01 de junho (terça-feira) acontecerá um evento na UNASP Hortolândia (Centro Universitário Adventista de São Paulo), na cidade de Hortolândia. Para quem é de Campinas e região, este evento acontecerá na sede da universidade, localizada na Rua Pr. Hugo Gegembauer, 265, Parque Hortolândia, à partir das 19:45. Eu palestrarei sobre o Visual Studio 2010 e o .NET Framework 4.0. É importante dizer que a palestra será de nível 100, que além de abordar superficialmente algumas das principais funcionalidades desta nova versão, falaremos um pouco também sobre algumas tecnologias que já existem e estão à disposição desde as versões anteriores. Abaixo temos a descrição da palestra:

Título: Visual Studio 2010 e .NET Framework 4.0
Palestrante: Israel Aece
Descritivo: Esta palestra tem a finalidade de exibir um “tour” sobre a plataforma .NET, e a principal ferramenta que utilizamos para desenvolver aplicações para ela, que é o Visual Studio. A ideia é demonstrar rapidamente a história e a evolução do .NET Framework até a versão 4.0, incluindo assuntos como as linguagens de programação (C# e VB.NET), acesso à dados e aplicações para internet (WebForms, MVC e Silverlight). Logo após, vamos analisar de forma superficial as novidades que estão sendo incluídas na IDE do Visual Studio 2010 e que dão suporte ao desenvolvimento de qualquer tipo de aplicação sobre a plataforma .NET.

Tags: , , ,

C# | Data | General | WCF

Community Launch em Campinas

by Israel Aece 15. March 2010 22:38

No próximo dia 20 de março acontecerá um evento chamado de Community Launch. Esse evento será espalhado por todo o Brasil, onde cada região criará o evento e abordará os principais produtos da Microsoft que estarão sendo lançados neste ano de 2010, a saber: Visual Studio 2010, Windows Server 2008 R2SQL Server 2008 R2.

Para quem é de Campinas e região, este evento acontecerá na Universidade UNIP, localizada no bairro Swift, à partir das 09:00 da manhã. Caso você não saiba exatamente onde ela está localizada, consulte este endereço para saber como chegar até lá. Entre as várias palestras, eu sou o responsável por falar sobre Visual Studio 2010 e .NET Framework 4.0. É importante dizer que a palestra será de nível 100, que além de abordar superficialmente algumas das principais funcionalidades desta nova versão, falaremos um pouco também sobre algumas tecnologias que já existem e estão à disposição desde as versões anteriores. Abaixo temos a descrição da palestra:

Título: Visual Studio 2010 e .NET Framework 4.0
Palestrante: Israel Aece
Descritivo: Esta palestra tem a finalidade de exibir um “tour” sobre a plataforma .NET, e a principal ferramenta que utilizamos para desenvolver aplicações para ela, que é o Visual Studio. A ideia é demonstrar rapidamente a história e a evolução do .NET Framework até a versão 4.0, incluindo assuntos como as linguagens de programação (C# e VB.NET), acesso à dados e aplicações para internet (WebForms, MVC e Silverlight). Logo após, vamos analisar de forma superficial as novidades que estão sendo incluídas na IDE do Visual Studio 2010 e que dão suporte ao desenvolvimento de qualquer tipo de aplicação sobre a plataforma .NET.

IMPORTANTE: Apesar do evento ser gratuito, para poder participar é necessário efetuar o cadastro aqui.

Tags: , , ,

.NET Framework | C# | Data | General | VB.NET

Problemas em arquivos de dados

by Israel Aece 29. October 2009 21:08

Até agora não entendi o motivo, mas repentinamente os arquivos que representam as estruturas de classes do LINQ To SQL e do Entity Framework deixaram de funcionar, ou melhor, o Visual Studio .NET deixou de exibir graficamente a estrutura de classes. O Server Explorer deixou de ser exibido; quando tentava criar um novo arquivo EDMX, o wizard simplesmente desaparecia; e quando tentava criar e/ou carregar um arquivo do LINQ To SQL, a seguinte mensagem era exibida: The operation could not be completed. The custom tool 'MSLinqToSQLGenerator' failed.  Could not retrieve the current project.

Depois de algumas pesquisas, cheguei à um blogue que dizia para excluir as sub-chaves que existiam dentro do seguinte path: HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\Packages. Basicamente o que tinha ali é uma chave chamada SkipLoading, que estava definida como "1". Antes de excluir, eu simplesmente mudei para "0", e tudo voltou a funcionar.

Tags: ,

Data

Utilizando o EF em Ambiente Parcialmente Confiável

by Israel Aece 16. July 2009 08:51

Estava utilizando a template de projeto Web Site para a criação de um site com uma vida curta, e que se destina a realizar uma tarefa temporária. Como ele deve acessar uma fonte de dados SQL Server para manipular alguns dados, optei por utilizar o Entity Framework como forma de acesso, ao invés do LINQ To SQL ou até mesmo do ADO.NET.

Em pouco tempo essa aplicação ficou pronta e tudo funcionava tranquilamente na máquina de desenvolvimento, até que decidi - erroneamente - configurar o Web.Config localmente. Entre essas configurações, uma delas foi ajustar o nível de segurança que a aplicação deverá rodar, que – teoricamente – não preciso nada mais do que o nível "Medium". Sendo assim, o meu arquivo Web.Config passou a ficar com a seguinte entrada:

<trust level="Medium" />

Ao tentar recompilar a aplicação no Visual Studio .NET, me deparo com o seguinte erro listado na IDE:

Type ‘System.Data.Entity.EntityDesignerBuildProvider’ cannot be instantiated under a partially trusted security policy (AllowPartiallyTrustedCallersAttribute is not present on the target assembly).

Ao abrir o arquivo Web.Config da aplicação, você notará que no elemento connectionStrings possuirá as referências para os arquivos que possuem as descrições das entidades e mapeamentos (CSDL, MSL e SSDL), acrescentado o prefixo "res://", que indica que eles serão adicionados ao assembly como Resource.

Além disso, você verá que existe um builder provider do tipo EntityDesignerBuildProvider, vinculado à aplicação. Essa classe é responsável por extrair as informações dos arquivos mencionados acima, e modificar os assemblies que estão sendo gerados, embutindo-as como Resources. Esse processo não pode ser executado em ambiente parcialmente confiável, já que a permissão necessária não será concedida à aplicação. Veja que a mensagem de erro informa que o Assembly onde está declarado este builder provider, não pode ser chamado por aplicações parcialmente confiáveis, pois a ausência do atributo AllowPartiallyTrustedCallersAttribute evita isso.

A transformação do arquivo EDMX (CSDL, MSL e SSDL) ocorre somente na primeira vez que se compila a aplicação (%windir%\Microsoft.NET\Framework\Versao\Temporary ASP.NET Files), e se nesse momento estiver com ela configurada como parcialmente confiável, assim como eu fiz acima, você irá obter o erro em questão. Se você optar por pré-compilar a aplicação em ambiente “FullTrust”, e fazer o deployment em ambiente parcialmente confiável, você não terá este problema. Isso é perfeitamente possível, já que as configurações de uma aplicação (Web.Config) não são compiladas.

Uma outra alternativa é utilizar o conceito de sandboxing, onde você isola o EDMX em uma Class Library, e faz referencia para ela no projeto Web. Como o arquivo EDMX estará embutido na DLL gerada, você não precisa mais das referências aos arquivos CSDL, MSL e SSDL na aplicação Web, e muito menos do build provider EntityDesignerBuildProvider no Web.Config. Neste caso, o ponto negativo é ter que gerenciar dois projetos e Assemblies.

Ainda há uma última alternativa neste caso, onde você extrai os arquivos CSDL, MSL e SSDL a partir do EDMX, e modifica a connectionString para apontar fisicamente para estes arquivos, que devem estar na mesma aplicação (talvez no diretório bin). Particularmente prefiro a opção da geração do Assembly a parte, que facilita a reutilização por várias aplicações e não corremos o risco de alguém, acidentalmente, excluir estes arquivos que são necessários para o Entity Framework trabalhar.

Tags: ,

ASP.NET | Data | Security

Queries compiladas

by Israel Aece 21. May 2009 16:59

Em várias aplicações é muito comum você ter que executar uma determinada query diversas vezes. Essas queries são utilizadas por diversos pontos do sistema e por diversos usuários. Quando estamos utilizando o LINQ To SQL ou o Entity Framework, a cada query que fazemos em C#/VB.NET, há uma série de procedimentos internos que são realizados para transformar/traduzir a query em T-SQL (ASTs).

Para evitar que esses procedimentos aconteçam a todo o momento, podemos recorrer a uma classe chamada CompiledQuery. Basicamente, a finalidade desta classe é otimizar a execução, que apenas efetua todos os procedimentos uma única vez, e faz o caching do “plano de execução” (em termos de entidades). E para fazer tudo isso funcionar, basta utilizar o método Compile, que esta classe disponibiliza. Esse método retorna um delegate do tipo Func<,,>, representando a query compilada, que por sua vez, especificará os tipos dos parâmetros necessários para ela, tais como, a fonte de dados (DataContext ou ObjectContext), os parâmetros de entrada e o resultado.

Vale lembrar que essa classe não é comum para ambas as tecnologias, ou seja, há uma versão dela para o Linq To SQL e outra para o Entity Framework, contidas nos namespaces System.Data.Linq e System.Data.Objects, respectivamente. O exemplo abaixo ilustra uma classe chamada DBQueries, que possui um membro estático chamado AreasDeUmaEmpresa, que representa uma query frequentemente utilizada em um determinada aplicação, e que faz uso do Linq To SQL como acesso a dados:

using System.Linq;
using System.Data.Linq;

internal static class DBQueries
{
    public static Func<DBContext, int, IEnumerable<Area>> AreasDeUmaEmpresa;

    static DBQueries()
    {
        AreasDeUmaEmpresa =
            CompiledQuery.Compile<DBContext, int, IEnumerable<Area>>(
                (db, empresaId) => from a in db.Areas where a.EmpresaID == empresaId select a);
    }
}

Abaixo está a mesma query, mas com uma ligeira modificação (não muito vísivel) para que funcione com o Entity Framework:

using System.Linq;
using System.Data.Objects;

internal static class DBQueries
{
    public static Func<DBEntities, int, IEnumerable<Area>> AreasDeUmaEmpresa;

    static DBQueries()
    {
        AreasDeUmaEmpresa =
            CompiledQuery.Compile<DBEntities, int, IEnumerable<Area>>(
                (db, empresaId) => from a in db.Areas where a.EmpresaID == empresaId select a);
    }
}

Como já sabemos, apesar de terem o mesmo nome, as classes CompiledQuery são tipos diferentes. O método Compile de cada uma delas possui uma constraint para o primeiro tipo genérico (TArg0), que identifica a fonte de dados, ou melhor, o contexto. No caso do LINQ To SQL, ele nos obrigará a definir esse primeiro parâmetro com um tipo que herde direta ou indiretamente da classe DataContext, enquanto a classe CompiledQuery utilizada pelo Entity Framework, determina que este mesmo parâmetro deve ser uma classe do tipo ObjectContext.

Em ambos os casos, armazenamos o resultado gerado pelo método Compile das respectivas classes CompiledQuery, em campos estáticos. Esse campo foi inicializado no construtor (também estático), mas talvez você possa fazer isso sob demanda. A idéia é criar um membro estático para armazenar cada query compilada, mantendo o resultado durante a execução da aplicação, reutilizando-a quando necessário.

Abaixo consta um exemplo de utilização da query compilada com LINQ To SQL. O Entity Framework seguirá a mesma idéia, apenas criando o contexto correspondente.

using (DBContext db = new DBContext())
    foreach (var item in DBQueries.AreasDeUmaEmpresa(db, 12)) { }

Queries compiladas tem uma performance consideravelmente melhor em relação as queries não compiladas, e usá-las poderá trazer bons ganhos de performance, podendo inclusive, utilizá-la em conjunto com o ConnectedDataContext. Mas também há um ponto negativo: você não conseguirá, de forma simples, projetar possíveis tipos anônimos que possam ser gerados através do select. Como tipos anônimos não podem ser propagados entre chamadas de métodos, então a única opção que nos resta é a criação de uma classe para armazenar e servir como wrapper para esse resultado.

Tags: , ,

Data

Model-First Development

by Israel Aece 23. April 2009 11:13

A versão atual do Entity Framework trabalha com o conceito conhecido como “database-first”. Neste caso, você precisa primeiramente criar a base de dados, definir as tabelas, as colunas e suas características, constraints e, depois disso, a IDE analisará todo o schema da mesma e irá construir o modelo de classes olhando para ele, inclusive levando em consideração os possíveis relcionamentos definidos, para tentar criar as associações entre as classes que farão parte do sistema. Quando você tiver tem uma base de dados que está bem definida e funcional, esse modelo é bem interessante, já que ele (re)utiliza todo o trabalho que foi realizado na construção da mesma, tendo apenas que acertar alguns detalhes.

Mas o mapeamento entre o mundo relacional e orientado a objetos é bem mais complexo do que isso. Nem sempre temos uma entidade por registro/tabela. Algumas características que são salvas no banco de dados como uma coluna normal, utilizando um tipo de dado convencional, no mundo orientado à objetos, isso pode ser representado por uma especialização (herança) ou até mesmo um outro objeto mais complexo que possui, além de suas características (propriedades), um funcionamento próprio (métodos e eventos). Esses são alguns dos “problemas” encontrados neste modelo de desenvolvimento que o Entity Framework atualmente possui.

Eu coloquei a palavra problemas entre aspas que, ao meu ver, isso é uma característica deste modelo e não uma deficiência. Aqueles que muitas vezes optam por iniciar no desenvolvimento da estrutura de classes da aplicação, não irá ter benefício nenhum do uso desta técnica. A partir da versão 2.0 do Entity Framework, que será lançada em conjunto com o .NET Framework 4.0 e o Visual Studio .NET 2010, irá incorporar o modelo de desenvolvimento conhecido como “model-first” que, como o próprio nome diz, baseando na estrutura de classes e suas associações, conseguirá extrair o modelo relacional, gerando os scripts necessários para a criação das tabelas, colunas e possíveis relacionamentos em uma base de dados.

Tags:

Data

Powered by BlogEngine.NET 1.5.0.0
Theme by Mads Kristensen

Sobre

Meu nome é Israel Aece e sou especialista em tecnologias de desenvolvimento Microsoft, atuando como desenvolvedor de aplicações para o mercado financeiro utilizando a plataforma .NET. [ Mais ]

Twitter

Indicações

Introdução ao ASP.NET Web API - e-Book