HttpClient na Portable Class Library

by Israel Aece 8. April 2013 22:19

É comum termos a necessidade de criar uma biblioteca com algum código que seja compartilhado entre diversos projetos. Para isso, recorremos à uma template de projeto chamada Class Library, em que seu output é um arquivo do tipo DLL, que pode ser referenciado e, consequentemente, utilizado por projetos que queiram utilizar a funcionalidade exportada por ela.

Tudo isso funcionará até o momento em que precisarmos expor uma determinada funcionalidade para diferentes plataformas, algo muito comum hoje no desenvolvimento de aplicações dentro do ambiente Microsoft. Possuimos diversos alvos que podemos atingir, como por exemplo: aplicações .NET, aplicações para telefones, aplicações para jogos (XBox), aplicações para tablets, etc. Apesar de existir certa simetria em alguns pontos, em outros já podem não ter tantas semelhanças assim, o que torna difícil o controle manual durante a escrita de uma biblioteca para atender qualquer uma estas plataformas.

Desde 2010 a Microsoft trabalha em um projeto para a criação de bibliotecas que possam ser compartilhadas entre diferentes plataformas, e com o Visual Studio 2012, já temos uma template de projeto exclusiva para isso: Portable Class Library. Ao criar um projeto deste tipo, você será obrigado a informar com quais tipos de projetos deseja que ela seja compatível. Isso garantirá com que você somente utilize membros que sejam comuns entre todas as plataformas selecionadas.

Geralmente algumas informações e funcionalidades estão expostas para serem consumidas remotamente, entre os mais diversos dispositivos. Sendo assim, é muito comum termos a necessidade de consumir os serviços expostos pela própria empresa, parceiros de negócios, etc., afim de reutilizar recursos que já estejam construídos e disponibilizados por terceiros. E como já era de se esperar, APIs REST estão cada vez mais populares, e ter um mecanismo para o consumo de forma simples destes tipos de serviços é essencial em qualquer plataforma.

Sabendo disso, a Microsoft criou uma classe chamada HttpClient, que é utilizada para abstrarir toda a complexidade na interação com APIs REST, e mais recentemente, a Microsoft criou a versão portável desta mesma classe. Com isso, poderemos reutilizar o consumo de APIs REST (HTTP) através de diferentes plataformas, sem a necessidade de reconstruir a cada novo projeto uma ponte de comunicação com estes tipos de serviços, e ainda, sem a necessidade de recorrer de classes de mais baixo nível para atingir o mesmo objetivo.

Em princípio a classe HttpClient fornece as mesmas funcionalidades expostas desde a sua criação, acrescentando alguns poucos métodos que expõem alguma funcionalidade específica para uma determinada plataforma. Para utilizar essa DLL em algum dos seus projetos (incluindo bibliotecas portáveis customizadas (Portable Class Libraries)), basta você adicionar o pacote "Http Client Libraries", conforme mostrado na imagem abaixo:

Tags: , ,

.NET Framework | CSD

Health Monitoring no ASP.NET MVC

by Israel Aece 1. April 2013 23:19

Há uma funcionalidade que foi criada no ASP.NET 2.0 chamada de Health Monitoring. Este recurso foi desenvolvido para servir como tratador de eventos que ocorrem em uma aplicação web. Utilizando um schema de configuração bastante elaborado, podemos customizar quais tipos de eventos queremos armazenar, onde será salvo, com qual periodicidade, intervalo, etc. Entre os tipos de eventos disponíveis, podemos citar: o sucesso e/ou falha no login, páginas não encontradas, erros não tratados, e assim por diante.

Apesar dela ter sido criada quando ainda não existia o ASP.NET MVC, isso não quer dizer que não pode utilizá-la com este tipo de projeto. O Health Monitoring trata-se de uma funcionalidade de "nível global", onde você poderá utilizar em qualquer tipo de projeto ASP.NET (WebForms ou MVC). Sendo assim, para habilitar este recurso em uma aplicação MVC, basta realizar uma configuração no arquivo Web.config, conforme é mostrado abaixo. Note que estamos optando por armazenar os eventos no Event Log do Windows:

<system.web>
  <healthMonitoring enabled="true">
    <rules>
      <clear />
      <add
        name="All Errors Default"
        eventName="All Errors"
        provider="EventLogProvider"
        profile="Default"
        minInterval="00:01:00"/>
    </rules>
  </healthMonitoring>
</system.web>

Vale lembrar que exceções não tratadas são catalogadas como esperado, porém o ASP.NET MVC possui um atributo chamado HandleErrorAttribute, que tem a finalidade de interceptar as requisições para este atributo quando uma exceção não tratada ocorre dentro da ação que está sendo requisitada, e ele, por sua vez, reencaminha a requisição para uma View padrão chamada Error, para exibir uma mensagem amigável ao usuário.

Para garantir que esta exceção também seja catalogada pelo Health Monitoring, é necessário criarmos um evento customizado, herdando da classe WebRequestErrorEvent. Essa classe será utilizada por uma customização da classe HandleErrorAttribute, onde invocaremos dentro do método OnException, o método Raise da classe WebRequestErrorEvent, passando a ele a exceção capturada pelo ASP.NET. Com isso, todas as exceções não tratadas serão encaminhadas para o atributo CatalogarErroNoHealthMonitoring, catalogadas pelo Health Monitoring e, finalmente, o usuário será redirecionado para a View Error (padrão do MVC).

public class CatalogarErroNoHealthMonitoring : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        base.OnException(filterContext);
        new DescricaoDeErro(this, filterContext.Exception).Raise();
    }
}

public class DescricaoDeErro : WebRequestErrorEvent
{
    private static readonly int eventCode = WebEventCodes.WebExtendedBase + 1;

    public DescricaoDeErro(object eventSource, Exception exception)
        : base("Exceção Não Tratada", eventSource, eventCode, exception) { }
}

Tags: , ,

ASP.NET

Virtualização do Reflection

by Israel Aece 10. July 2012 00:03

Reflection é uma técnica que utilizamos no .NET para lidar diretamente com os metadados, ou seja, extrair quais são os campos, propriedades, métodos, eventos, atributos, etc., para que possamos criar um código dinâmico, com o intuito de inspecionar ou até mesmo alterar valores ou a execução baseado no que temos em cada um dos tipos.

Uma das técnicas utilizadas pelo próprio .NET Framework, e também por nós, é a criação ou utilização de atributos que nos permitem decorar em diversos membros, para que eles guiem a execução, permitindo ao consumidor destes tipos, a ler e interpretá-los de acordo com uma determinada regra. Para exemplificar, abaixo temos alguns casos de uso destas técnicas:

  • O Visual Studio utiliza atributos decorados nas propriedades das classes (controles), para exibir cada uma delas na janela de propriedades da IDE.
  • O WCF obriga a interface que define o contrato do serviço estar decorada com o atributo ServiceContractAttribute.
  • Utilizamos o atributo AuthorizeAttribute para refinar o acesso às ações dos controllers do ASP.NET MVC.
  • Alguma funcionalidade específica em vossa aplicação.

Partindo deste princípio, podemos ter um atributo customizado que utilizamos para decorar em propriedades de um determinado tipo. Esse atributo basicamente define um rótulo customizado para cada propriedade onde ele é aplicado. Abaixo temos o atributo e a classe já fazendo uso do mesmo:

public class Exibicao : Attribute
{
    public string Label { get; set; }
}

public class LinhaDeRegistro
{
    [Exibicao(Label = "Nome")]
    public string Nome { get; set; }

    [Exibicao(Label = "Código")]
    public int Codigo { get; set; }

    [Exibicao(Label = "Valor")]
    public decimal Valor { get; set; }

    public DateTime DataDaOcorrencia { get; set; }
}

É importante dizer que o atributo por si só não serve para nada. Precisamos de um código que o consuma e faça alguma coisa com ele. Para isso, temos um método que percorre as propriedades do objeto, e para cada uma delas, verifica se existe o atributo recém criado, e se existir, exibe a informação formatada utilizando o rótulo que foi definido durante o desenvolvimento.

public static void ExibirColunas(Type type, object value)
{
    foreach (var p in new type.GetProperties())
    {
        var a = p.GetCustomAttribute(typeof(Attribute)) as Exibicao;

        if (a != null)
            Console.WriteLine(
                "{0}: {1}", a.Label, p.GetValue(value, null));
    }
}

Com este método criado, podemos fazer o uso dele passando o objeto contendo as informações e também o seu tipo. Apesar de conseguir extrair o Type no interior do próprio método, optei por deixar propositalmente via parâmetro, que mais tarde isso fará sentido. Abaixo o código que chama este método:

var linha = new LinhaDeRegistro()
{
    Codigo = 1,
    Nome = "Israel",
    Valor = 12000,
    DataDaOcorrencia = DateTime.Now
};

ExibirColunas(linha.GetType(), linha);

Ao rodar a aplicação, o resultado será:

Nome: Israel
Código: 1
Valor: 12000

Como percebemos, o valor da propriedade DataDaOcorrencia não é exibida. Mas faz sentido, pois ela não foi decorada com o atributo Exibicao que criamos acima. Para resolver isso, basta, também, decorar o atributo na propriedade, compilar e rodar, que a informação será exibida conforme o esperado. Mas como faremos isso, se a classe LinhaDeRegistro está em um outro assembly, onde não temos acesso ao código fonte?

Para sanar esse problema, podemos recorrer à classe CustomReflectionContext, que está debaixo do namespace e assembly System.Reflection.Context.dll. Esse assembly faz parte do .NET Framework 4.5, que externaliza as capacidades de reflection de um determinado objeto, sem a necessidade de recriar um modelo total para isso.

A implementação padrão da classe abstrata CustomReflectionContext, simplesmente serve como um wrapper, sem qualquer mudança em relação ao tradicional. Mas isso nos dá a chance de customizar a criação de um novo contexto de reflection, e sobrescrevendo alguns métodos, nós podemos adicionar, remover ou alterar atributos ou até mesmo adicionar novas propriedades aos tipos que estamos manipulando.

Para exemplificar a sua utilização, criamos um contexto customizado, onde sobrescrevemos o método GetCustomAttributes, identificamos se o membro trata-se da propriedade DataDaOcorrencia, e se for, retornamos um atributo Exibicao configurado conforme é necessário por nossa aplicação (ou seja, pelo método ExibirColunas).

public class ContextoParaExibicao : CustomReflectionContext
{
    protected override IEnumerable<object> GetCustomAttributes(MemberInfo member,
        IEnumerable<object> declaredAttributes)
    {
        if (member.Name == "DataDaOcorrencia")
            return new[] { new Exibicao() { Label = "Data da Ocorrência" } };

        return base.GetCustomAttributes(member, declaredAttributes);
    }
}

Finalmente, depois da criação deste contexto, precisamos utilizá-lo, e para isso, o instanciamos e chamamos o método MapType, que recebe como parâmetro um objeto do tipo TypeInfo, que também novo no .NET 4.5, e caracteriza a parte de "reflection" de um determinado tipo. Como essa classe herda da classe Type, podemos utilizar o retorno deste método, e passar diretamente para o método consumidor, sem a necessidade de alterar nada em seu interior:

ExibirColunas(
    new ContextoParaExibicao().MapType(linha.GetType().GetTypeInfo()),
    linha);

Apesar de algumas soluções já existirem no .NET Framework (TypeDescriptor e PropertyDescriptor) para tentar extrair essas mesmas informações, provendo também tipos específicos para a customização da extração (ICustomTypeDescriptor), o time do .NET Framework/CLR decidiu incorporar isso diretamente no .NET Framework, o que pode ser utilizado por todos aqueles que desejam essa funcionalidade, de dentro ou fora da Microsoft.

Tags: ,

.NET Framework

Geração de Documentação para ASP.NET WebApi

by Israel Aece 3. June 2012 15:35

Há algum tempo eu comentei aqui sobre REST e WSDL, onde a ideia era apontar a maneira de se trabalhar com serviços sem a necessidade de ter um schema que define o que serviço disponibiliza e, principalmente, toda a estrutura das mensagens (SOAP) que são trocadas entre as partes.

Mas é importante dizer que mesmo serviços baseados em REST, também precisam, de alguma forma, expor alguma espécie de documentação, para descrever as ações que as APIs estão disponibilizando aos consumidores, apontando o caminho (URI) até aquele ponto, método/verbo (HTTP), informações que precisam ser passadas, formatos suportados, etc.

A ideia é apenas ser informativo, ou seja, isso não será utilizado pelo cliente para a criação automática de uma proxy. Pensando nisso, a Microsoft incluiu no ASP.NET Web API a opção para gerar e customizar as documentações de uma API.

Mas a documentação é sempre exibida, na maioria das vezes, de forma amigável ao consumidor, para que ele possa entender cada uma das ações, suas exigências, para que ele possa construir as requisições da forma correta. Sendo assim, podemos na própria aplicação onde nós temos as APIs, criar um controller que retorna uma view (HTML), contendo a descrição das APIs que estão sendo hospedadas naquela mesma aplicação.

public class DeveloperController : Controller
{
    public ActionResult Apis()
    {
        var explorer = GlobalConfiguration.Configuration.Services.GetApiExplorer();

        return View(explorer.ApiDescriptions);
    }
}

Note que estamos recorrendo ao - novo - método GetApiExplorer, disponibilizado através da configuração global das APIs. Este método retorna um objeto que implementa a interface IApiExplorer, que como o próprio nome sugere, define a estrutura que permite obter a descrição das APIs. Nativamente já temos uma implementação chamada ApiExplorer, que materializa todoas as APIs em instâncias da classe ApiDescription, e uma coleção deste objeto é retornada através da propriedade ApiDescriptions, e que repassamos para que a view possa renderizar isso.

Na view, tudo o que precisamos fazer é iterar pelo modelo, e cada elemento dentro deste laço representa uma ação específica que está dentro da API. A classe que representa a ação, possui várias propriedades, fornecendo tudo o que é necessário para que os clientes possam consumir qualquer ums destas ações. Abaixo temos o código que percorre e exibe cada uma delas:

@model IEnumerable<System.Web.Http.Description.ApiDescription>

<body>
    @foreach (var descriptor in this.Model)
    {
        <ul>
            <li><b>@descriptor.HttpMethod - @descriptor.RelativePath</b></li>
            <li>Documentation: @descriptor.Documentation</li>

            @if (descriptor.SupportedResponseFormatters.Count > 0)
            {
              <li>Media Types
                <ul>
                  @foreach (var mediaType in descriptor.SupportedResponseFormatters.Select(
                     mt => mt.SupportedMediaTypes.First().MediaType))
                  {
                    <li>@mediaType</li>
                  }
                </ul>
              </li>
            }

            @if (descriptor.ParameterDescriptions.Count > 0)
            {
              <li>Parameters
                  <ul>
                    @foreach (var parameter in descriptor.ParameterDescriptions)
                    {
                      <li>Name: @parameter.Name</li>
                      <li>Type: @parameter.ParameterDescriptor.ParameterType</li>
                      <li>Source: @parameter.Source</li>
                    }
                  </ul>
              </li>
            }
        </ul>
    }
</body>

Ao acessar essa view no navegador, temos a relação de todas as ações que estão expostas pelas APIs. A visibilidade das ações é controlada a partir do atributo ApiExplorerSettingsAttribute, que possui uma propriedade boleana chamada IgnoreApi, que quando definida como True, omite a extração e, consequentemente, a sua visualização.

É importante notar que na imagem acima, estamos apresentando a propriedade Documentation. A mensagem que aparece ali é uma customização que podemos fazer para prover essa informação, extraindo-a de algum lugar. Para definir a descrição da ação, vamos criar um atributo customizado para que quando decorado no método, ele será extraído por parte da infraestrutura do ASP.NET, alimentando a propriedade Documentation. O primeiro passo, consiste na criação de um atributo para definir a mensagem:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class ApiDocumentationAttribute : Attribute
{
    public ApiDocumentationAttribute(string message)
    {
        this.Message = message;
    }

    public string Message { get; private set; }
}

O próximo passo é decorá-lo em cada uma das ações que quisermos apresentar uma informação/descrição. A classe abaixo representa a nossa API, e o atributo recentemente criado foi decorado em todas as ações, descrevendo suas respectivas funcionalidades:

public class ClientesController : ApiController
{
    [ApiDocumentation("Retorna todos os clientes.")]
    public IEnumerable<Cliente> Get()
    {
        //...
    }

    [ApiDocumentation("Retorna um cliente pelo seu Id.")]
    public Cliente Get(int id)
    {
        //...
    }

    [ApiDocumentation("Inclui um novo cliente.")]
    public void Post(Cliente cliente)
    {
        //...
    }

    [ApiDocumentation("Exclui um cliente existente.")]
    public void Delete(int id)
    {
        //...
    }
}

Só que o atributo por si só não funciona. Precisamos de algum elemento para extrair essa customização que fizemos, e para isso, a temos uma segunda interface, chamada IDocumentationProvider, que fornece dois métodos com o mesmo nome: GetDocumentation. A diferença entre eles é o parâmetro que cada um deles recebe. O primeiro recebe um parâmetro do tipo HttpParameterDescriptor, o que permitirá descrever, também, cada um dos parâmetros de uma determinada ação. Já o segundo método, recebe um parâmetro do tipo HttpActionDescriptor, qual utilizaremos para extrair as informações pertinentes à uma ação específica.

public class ApiDocumentationAttributeProvider : IDocumentationProvider
{
    public string GetDocumentation(HttpParameterDescriptor parameterDescriptor)
    {
        return null;
    }

    public string GetDocumentation(HttpActionDescriptor actionDescriptor)
    {
        var attributes =
            actionDescriptor.GetCustomAttributes<ApiDocumentationAttribute>();

        if (attributes.Count > 0)
            return attributes.First().Message;

        return null;
    }
}

Aqui extraímos o atributo que criamos, e se ele for encontrado, retornamos o valor definido na propriedade Message. A ausência deste atributo, faz com que um valor nulo seja retornado, fazendo com que nenhuma informação extra seja incluída para a ação.

E, finalmente, para incluir o provedor de documentação ao runtime do ASP.NET, recorremos à configuração das APIs, substituindo qualquer implementação existente para este serviço, para o nosso provedor que extraí a documentação do atributo customizado.

GlobalConfiguration.Configuration.Services.Replace(
    typeof(IDocumentationProvider),
    new ApiDocumentationAttributeProvider());

Tags: , ,

ASP.NET | CSD

Recursos da Palestra do MVC Summit 2012

by Israel Aece 19. May 2012 20:49

 

Acabei de efetuar uma palestra no MVC Summit 2012. Entre os vários temas que foram discutidos sobre o desenvolvimento Web, eu falei sobre o ASP.NET Web API, que pode ser utilizado para a construção de serviços baseados em REST. Peço desculpas, mas infelizmente não houve tempo suficiente para abrir para perguntas e respostas, então para aqueles que gostaríamos de fazer algum questionamento, peço encarecidamente para que vocês coloquem nos comentários deste post, ou se desejarem, podem me contatar diretamente através da seção de contato.

Gostaria imensamente de agradecer a todos os presentes, e também ao Vinicius Quaiato, Andre Baltieri, Victor Cavalcante e ao Alexandre Tarifa por esta oportunidade. Para aqueles interessados, o download do projeto pode ser baixado clicando aqui, e se desejarem, aqui também estão os slides da apresentação.

Tags: , ,

CSD | General | WCF

Substituindo o Framework de AOP

by Israel Aece 7. May 2012 23:28

Quando desenvolvemos um software, ou uma parte dele, além da parte relacionada ao negócio em si, nas maioria das vezes, precisamos recorrer a códigos de infraestrutura, que são responsáveis por gerenciar alguns recursos que estão indiretamente relacionados ao processo.

Geralmente mencionamos o termo cross-cutting concerns, que se referem a funcionalidades que podem se estender e afetar várias partes do sistema. Autenticação, Autorização, Logging e Transação, são algumas das funcionalidades que poderiam ser candidatas a serem encaradas e implementadas desta forma.

Apesar de possível, não é interessante misturar este tipo de funcionalidade com o código de negócio, pois facilmente você poderá agregar mais funcionalidade do que deveria. Além disso, a modularização é extremamente importante, pois facilita a manutenção, e eventuais alterações mais complexas. Como estas funcionalidades interceptam várias partes do sistema e em diversos níveis, uma das formas mais comuns de se acoplar isso à execução, é através da técnica de AOP, Aspect Oriented Programming.

Em .NET, existe um framework chamado PostSharp. Este é um framework fornece alguns atributos para decorar em elementos do nosso código, e onde o aplicamos, ele utilizará IL Weaving durante a compilação, reescrevendo o código para adicionar os comportamentos necessários, e durante a execução, serão executados de forma automática (e mágica?), sem que o nossos códigos de negócios mencionem diretamente funcionalidades de cross-cutting.

Apesar do framework fazer um grande trabalho, reescrevendo a IL para injetar o código customizado em torno do local onde o aplicamos, poderíamos trabalhar de forma semelhante, sem qualquer mágica envolvida. Tudo isso, utilizando apenas classes customizadas, onde você poderá ter o controle total, e tudo isso, sem a necessidade de envolver algum framework de terceiro.

Para exemplificar, podemos criar uma classe que representa um comando a ser executado. Basicamente, cada comando carrega as informações necessárias para que o mesmo possa ser executado, como por exemplo: criar, configurar e por fim, gravar um novo cliente na base de dados. Mas o comando por si só não funcionará. Isso quer dizer que vamos precisar de um tratador, ou seja, aquele que irá recepcionar o comando (que contém os dados), executando-o para que o cliente seja efetivamente gravado na base de dados.

Neste comando, poderíamos envolvê-lo em um bloco transacionado, efetuar o logging de algumas informações, mensurar o tempo de execução, etc. Mas como dito acima, colocar códigos de cross-cutting aqui, faria com que tivessemos algumas outras preocupações, e isso, voltaria a acontecer em todos os comandos que nossa aplicação venha a ter. Redundância e descentralização seriam alguns dos problemas que poderíamos enfrentar, sem contar a eventual necessidade de ter que injetar dependências indiretas ao comando (aquelas exigidas pela infraestrutura).

Abaixo temos o diagrama de classes que resume todos os tipos utilizados na solução. Classes sufixidas com a palavra "Handler", correspondem aos tratadores dos comandos, e como eles estão implementados no formato de russian-dolls, podemos adicionar um dentro do outro, fazendo com que eles sejam executados antes ou depois do outro comando que você adicionou.

Repare que no código abaixo, LogingHandler, ele herda da classe abstrata CommandHandler, recebendo em seu construtor a instância de um próximo comando, qual será executado "entre este comando".

public class LoggingHandler : CommandHandler
{
    private readonly CommandHandler next;

    public LoggingHandler(CommandHandler next)
    {
        this.next = next;
    }

    protected override void ExecuteInternal(Command command)
    {
        Console.WriteLine("* Início da Execução do Comando.");
        this.next.ExecuteCommand(command);
        Console.WriteLine("* Fim da Execução do Comando.");
    }
}

Se evoluirmos um pouco mais o código, podemos criar métodos de extensão, para que cada um deles seja responsável por retornar um novo tratador, envolvendo nele o tratador atual, aquele onde está sendo aplicado a estensão. Neste caso, podemos nomear os métodos, de acordo com a funcionalidade que cada um deles agrega à execução:

public static class Estensoes
{
    public static CommandHandler ComTransacao(this CommandHandler handler)
    {
        return new TransactionHandler(handler);
    }

    public static CommandHandler MedindoTempo(this CommandHandler handler)
    {
        return new TimerHandler(handler);
    }

    public static CommandHandler GerandoLog(this CommandHandler handler)
    {
        return new LoggingHandler(handler);
    }
}

Como os métodos de estensão criados acima estão sendo aplicados ao tipo CommandHandler, podemos agregar ao mesmo qualquer uma das funcionalidades, de uma "forma fluente". Com todos os tratadores do diagrama acima implementados, podemos escrever um código parecido com esse:

new CadastrarClienteHandler()
    .ComTransacao()
    .GerandoLog()
    .MedindoTempo()
    .ExecuteCommand(new CadastrarCliente() { Nome = "Israel" });

E, finalmente, o resultado depois da execução:

  • Início da Execução do Comando 'CadastrarCliente'.
  • Início do Bloco Transacionado.
  • Cadastrando o Cliente 'Israel'.
  • Commit da Transação.
  • Fim do Bloco Transacionado.
  • Fim da Execução do Comando 'CadastrarCliente'.
  • Tempo Decorrido: 00:00:00.0042806.

Tags: , ,

C#

Configuração dinâmica no WCF

by Israel Aece 24. April 2012 23:35

Existem duas formas de configurar um serviço WCF: imperativa e declarativa. A primeira opção consiste em criar explicitamente a classe ServiceHost, configurá-la e gerenciar a sua execução, e tudo isso é feito diretamente através da linguagem (C# e VB.NET). Já no modelo declarativo, recorremos ao arquivo de configuração (App.config ou Web.config), onde tudo é configurado dentro deles, o que te dá uma maior flexibilidade, já que te permite alterar mesmo depois de instalado no servidor.

Quando queremos algum dinamismo na configuração do serviço, podemos recorrer a primeira opção. Mas quando estamos hospedando o serviço em um projeto Web, através de um arquivo *.svc, a construção da classe ServiceHost é criada automaticamente pelo WCF/ASP.NET.

Nestes casos, para conseguir atingir o nosso objetivo, devemos construir uma factory customizada, e para isso, precisamos criar uma classe herdando de ServiceHostFactory, sobrescrever o método CreateServiceHost, onde dentro dele, criaremos o ServiceHost de acordo com nossa necessidade e, finalmente, acoplamos  à execução através da diretiva @ServiceHost no arquivo *.svc. Mais detalhes aqui.

Na versão 4.5 do WCF, a Microsoft facilitou isso, sem a necessidade de fazer várias customizações e configurações. Basicamente colocamos na classe que representa o serviço, um método estático chamado Configure, que receberá como parâmetro a instância da classe ServiceConfiguration, e como o próprio nome diz, corresponde as configurações daquele serviço, e que será aplicado ao ServiceHost. O código abaixo ilustra este novo recurso. Isso irá eliminar tudo aquilo que fazíamos até então, para conseguir customizar e/ou gerar a configuração para os serviços que são hospedados no IIS.

public class Servico : IContrato
{
    public static void Configure(ServiceConfiguration config)
    {
        config.Description.Behaviors.Add(
            new ServiceMetadataBehavior() { HttpGetEnabled = true });

        config.Description.Behaviors.Add(
            new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
    }

    public string Ping(string value)
    {
        return value + " ping";
    }
}

Tags:

WCF

Compressão no .NET Framework 4.5

by Israel Aece 24. April 2012 00:28

Há algum tempo, eu falava aqui sobre compressão de arquivos no .NET Framework. Temos à disposição as classes GZipStream e DeflateStream para manipular arquivos, ou melhor, conteúdos que necessitam ser compactados ou descompactados utilizando estes dois algoritmos (Deflate e GZip).

Apesar de funcionar em alguns cenários, é um pouco difícil trabalhar em situações mais comuns quando precisamos lidar com (des)compactação. Um exemplo típico é quando precisamos compactar um diretório todo, ou múltiplos arquivos em um único arquivo *.zip. Além disso, toda a manipulação precisa ser realizada através do uso de streams, ou seja, temos que lidar com a alocação e cópia dos bytes entre a origem e o destino.

Como as operações comuns são as mais complicadas de serem utilizadas, recorremos à frameworks externos, como é o caso do SharpZipLib, que fornece várias funcionalidades interessantes acerca da utilização de ZIPs. Finalmente, a partir da versão 4.5 do .NET Framework, a Microsoft incluiu novas classes que visa facilitar a manipulação destes tipos de arquivos em aplicações .NET.

Apesar dos novos tipos estarem debaixo do namespace System.IO.Compression, eles são fornecidos através da referência de novos assemblies que fazemos em nossas aplicações: System.IO.Compression.dll e System.IO.Compression.FileSystem.dll. O primeiro assembly fornece os tipos de mais baixo nível para trabalhar com ZIP; já as classes disponíveis dentro do segundo assembly, temos apenas alguns utilitários (classes estáticas) que tornam ainda mais fácil a geração e consumo de ZIPs pela aplicação.

A primeira classe que vamos falar é a ZipArchive, que corresponde a um pacote de arquivos comprimidos, que pode ser um ou N arquivos. Para cada conteúdo (arquivo) dentro do ZipArchive, existe uma classe que o descreve: ZipArchiveEntry. E como já era de se esperar, a classe ZipArchive fornece uma propriedade chamada Entries, que retorna a coleção de entradas, e podemos notar isso na imagem abaixo:

A classe ZipArchiveEntry não é criada diretamente, ou seja, através de um construtor público. A primeira opção para a sua criação, é através do método CreateEntry da classe ZipArchive, que recebe como parâmetro o nome da entrada, e que muitas vezes, se você estiver compactando um arquivo, o nome da entrada pode refletir o nome do arquivo que está sendo inserido.

No exemplo abaixo, abrimos a conexão com um arquivo de destino via FileStream. Esse arquivo será o arquivo compactado, ou seja, as entradas criadas serão colocadas nele. O stream que aponta para o arquivo Dados.zip, é passado no construtor da classe ZipArchive, e logo em seguida, percorremos os arquivos do diretório C:\Temp, onde para cada arquivo, criamos uma entrada dentro do ZipArchive. Por fim, copiamos o conteúdo do arquivo da origem para o destino, ainda operando com streams. O código abaixo ilustra este trabalho:

using (var output = new FileStream("Dados.zip", FileMode.Create))
using (var archive = new ZipArchive(output, ZipArchiveMode.Create))
    foreach (var filename in Directory.GetFiles(@"C:\Temp\"))
        using (var source = File.Open(filename, FileMode.Open))
        using (var destination = archive.CreateEntry(Path.GetFileName(filename)).Open())
            source.CopyTo(destination);

Ao rodar esse código, efetuamos a compactação de todos os arquivos que estão no diretório C:\Temp. Para os testes, existem dois arquivos neste diretório, totalizando cerca de 11 MB. E depois de serem compactados, e colocados no arquivo Dados.zip, o valor cai para 316 KB, assim como podemos perceber através da imagem abaixo:

Como comentei acima, com o intuito de facilitar ainda mais a criação de conteúdo compactado, vamos reescrever este código utilizando um novo método de estensão, chamado CreateEntryFromFile, que dado o arquivo de origem e o nome da entrada, ele automaticamente cria a mesma, já copiando todo o conteúdo para dentro dela. Vemos que o código fica mais simples ao utilizar essa opção:

using (var output = new FileStream("Dados.zip", FileMode.Create))
using (var archive = new ZipArchive(output, ZipArchiveMode.Create))
    foreach (var filename in Directory.GetFiles(@"C:\Temp\"))
        archive.CreateEntryFromFile(
            filename,
            Path.GetFileName(filename),
            CompressionLevel.Optimal);

E para facilitar ainda mais, temos um método estático disponível através da classe ZipFile, chamado CreateFromDirectory, que dado o endereço do diretório e o caminho para o arquivo de destino, ele já cria as entradas para cada arquivo, copia o conteúdo e, finalmente, gera o arquivo compactado. Por fim, em uma única linha, conseguimos reescrever os mesmos códigos que vimos acima:

ZipFile.CreateFromDirectory(@"C:\Temp", @"C:\Dados.zip");

Este método ainda fornece um overload, que além de permitir informar o nível da compactação, recebe um boleano, indicando se a pasta que está sendo compactada, deve ou não ser incluída como raiz do arquivo compactado. Abaixo, as imagens mostram quando utilizamos true, e logo na sequência, false, para este parâmetro:

ZipFile.CreateFromDirectory(
            @"C:\Temp",
            @"C:\Dados.zip",
            CompressionLevel.Optimal,
            true);

A extração do arquivo compactado para os arquivos isolados, são trabalhados de forma semelhante. E da mesma forma que na compactação, a descompactação também fornece alguns métodos utilitários que podem ser utilizados para realizar a extração dos arquivos que estão dentro do arquivo *.zip. Para exemplificar, no código abaixo, fazemos o uso do método estático ExtractToDirectory, exposto pela classe ZipFile. Este método recebe como fonte, o arquivo compactado, e o segundo parâmetro, corresponde ao caminho onde queremos extrair todo o conteúdo:

ZipFile.ExtractToDirectory(@"C:\Dados.zip", @"C:\Output\");

Tags:

.NET Framework

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

Host