Exceções dentro de Recursos Voláteis

O .NET Framework já fornece nativamente suporte para a criação de contextos transacionais através da classe TransactionScope. Além da possibilidade de alistar automaticamente recursos como base de dados, message queue, etc., é possível customizar e alistar também recursos voláteis, onde podemos customizar e proteger algum código que queremos que seja efetivado quando ocorrer o commit, ou desfeito se o rollback ocorrer.

Para essa customização, basta implementarmos a interface IEnlistmentNotification, que fornece os métodos específicos e permite ao recurso interceptar cada um dos momentos definidos pelo protocolo 2PC (two phase commit): prepare, commit e rollback. Uma implementação simples desta interface é exibida abaixo. É importante notar que dentro do construtor já avaliamos se a classe está sendo instanciada dentro de um ambiente transacionado, e se sim, já alistamos o recurso para ser notificado quando os respectivos eventos ocorrer.

public class Teste1 : IEnlistmentNotification
{
    public Teste1()
    {
        if (Transaction.Current != null)
            Transaction.Current.EnlistVolatile(
                this, EnlistmentOptions.EnlistDuringPrepareRequired);
    }

    public void Commit(Enlistment enlistment) { }

    public void InDoubt(Enlistment enlistment) { }

    public void Prepare(PreparingEnlistment preparingEnlistment) { }

    public void Rollback(Enlistment enlistment) { }
}

Os métodos são autoexplicativos. Mas vamos focar no método Prepare. Este método é disparado durante a primeira fase do protocolo 2PC, onde o gerenciador interrogando o recurso se pode ou não realizar o commit. É importante falarmos sobre o disparo de exceções aqui. É importante envolvermos todo o código que está dentro deste método em um bloco try/catch, pois se houver uma exceção não tratada aqui, isso fará com que o .NET aborte os métodos de rollbacks de outros recursos que estejam também alistados. Imagine que o método Rollback acima esteja implementado da seguinte forma:

public void Prepare(PreparingEnlistment preparingEnlistment)
{
    throw new Exception("Erro no Teste1.");
}

Para provar que o problema de fato ocorre, vamos criar uma segunda classe que implemente esta mesma interface, e em seu método Rollback, simplesmente vamos escrever uma mensagem na tela. Conside o código abaixo, que instancia as duas classes (ambas implementam a interface em discussão aqui), e quando o método Prepare é chamado sobre o objeto teste1 disparando a exceção não tratada, o .NET aborta o resto e, consequentemente, o método Rollback do objeto teste2 não é disparado.

using (var transaction = new TransactionScope())
{
    var teste1 = new Teste1();
    var teste2 = new Teste2();

    transaction.Complete();
}

O comportamento que esperamos não é este, ou seja, temos também que garantir que o Rollback seja disparado com sucesso nos demais objetos que estão a seguir e fazem parte do mesmo contexto transacional. Para resolvermos isso, basta proteger o código do método Prepare em um bloco try/catch, e se algum problema ocorrer, basta chamar o método ForceRollback, indicando ao runtime do .NET que a transação deve ser desfeita. E ainda, se quiser prover informações adicionais sobre o problema ocorrido, basta capturar a exceção e informando-a para um overload deste mesmo método, que passa adiante o problema (via InnerException), protegendo toda stack trace e entregando a mensagem real do problema. Sendo assim, a implementação final é:

public void Prepare(PreparingEnlistment preparingEnlistment)
{
    try
    {
        throw new Exception("Erro no Teste1");

        preparingEnlistment.Prepared();
    }
    catch (Exception ex)
    {
        preparingEnlistment.ForceRollback(ex);
    }
}
Publicidade

MessageQueue e HTTP

Quando trabalhamos com o Microsoft Message Queue, serviço de mensagens fornecido pelo Windows, ele nos permite expor as filas através do protocolo HTTP. Isso permitirá apenas o envio de mensagens através deste protocolo (podendo também ser via HTTPS), e com isso, clientes que estiverem além dos limites da empresa, poderão enfileirar mensagens para o processamento interno de alguma rotina que rodará periodicamente.

Apenas o envio é permitido via HTTP, pois somente a porta 80 é necessária para executar esta ação; para recepcionar a mensagem, é exigido que outras portas também estejam abertas no firewall, e devido a isso, a Microsoft optou por não permitir o recebimento de mensagens sobre estes protocolos.

Para fazer uso deste recurso, ao instalar o Message Queue no computador que receberá as mensagens, você deve marcar a opção de suporte ao protocolo HTTP, conforme é mostrado na imagem abaixo. Vale lembrar que esta opção exige que o IIS (Internet Information Services) também esteja instalado nesta mesma máquina.
Depois de instalado, o Message Queue cria uma diretório virtual dentro do IIS, que servirá o ponto de acesso (HTTP/S) para as filas criadas nesta máquina. Abaixo vemos a fila chamada “Exemplo” criada e o diretório virtual chamado “MSMQ”.
Por fim, ao fazer uso da API System.Messaging, podemos apontar para o endereço HTTP, combinando o diretório virtual criado com o nome da fila para qual queremos enviar a mensagem.

using (var mq = new MessageQueue(“FormatName:DIRECT=http://localhost/msmq/private$/exemplo”))
    mq.Send(“Algo Aqui”, MessageQueueTransactionType.Single);

Apesar disso ser possível, considere o uso do WCF com MessageQueue.

Testes com a classe TelemetryClient

No artigo anterior eu mostrei o uso da classe TelemetryClient para catalogar informações customizadas. O fato de utilizar a classe em sua configuração padrão, fará com que as informações sejam enviadas para o serviço (na nuvem) mesmo que você ainda esteja em ambiente de testes. Talvez isso não seja o que estamos querendo, pois espalhamos pelo código os pontos que são cruciais para enviar as informações, mas talvez só faça sentido quando estive em ambiente de produção.

A classe TelemetryClient confia nas configurações que são disponibilizadas pela classe TelemetryConfiguration. Ela, por sua vez, possui uma propriedade estática chamada Active que retorna as configurações globais (para a aplicação) do Application Insights. A partir daí podemos recorrer a propriedade DisableTelemetry que quando definida como true, não enviará as informações ao serviço. Para utiliza-la podemos também condicionar à diretiva de DEBUG para somente desabilitar enquanto estivermos em desenvolvimento:

#if DEBUG
            TelemetryConfiguration.Active.DisableTelemetry = true;
#endif

Ainda com o exemplo utilizado no artigo anterior, não estávamos nos preocupando com os testes unitários. É uma preocupação que também devemos ter para não reportar os eventos quando estamos rodando os testes. Apesar da opção acima resolver, as vezes podemos querer validar se o nosso código está ou não reportando quando necessário e se as informações que foram levadas estão de acordo com a nossa expectativa.

A classe de configuração também nos permite configurar o canal de comunicação, e com isso customizar (sobrescrever) onde e como queremos armazenar os logs. Só que antes de visualizarmos o código necessário para alcançar isso, vamos entender a dependência entre a classe TelemetryClient e o restante da configuração.

A classe TelemetryClient possui dois overloads, onde um deles espera a instância da classe TelemetryConfiguration, que se for omitida, o Application Insights utiliza o valor fornecido pela propriedade Active. A classe TelemetryConfiguration possui uma propriedade chamada TelemetryChannel, onde podemos customizar o canal de comunicação através da implementação da interface ITelemetryChannel. Para o exemplo, vou optar por armazenar os logs em uma coleção interna, conforme é possível ver no código abaixo:

public class TestChannel : ITelemetryChannel
{
    private readonly IList<ITelemetry> itens;

    public TestChannel()
    {
        this.itens = new List<ITelemetry>();
    }

    public void Send(ITelemetry item)
    {
        this.itens.Add(item);
    }

    public IList<ITelemetry> Itens
    {
        get
        {
            return this.itens;
        }
    }

    //outros membros, omitidos por questão de espaço
}

Depois da classe implementada, precisamos criar a instância e associa-la à propriedade da configuração para que ela passe a ser utilizada quando chamarmos os métodos para catalogar as informações (Track*). O código que foi criado para calcular o frete não foi alterado em nada. Mesmo que a configuração tenha sido realizada externamente, a classe TelemetryClient irá utilizar esta classe via TelemetryConfiguration (via propriedade Active). O teste ficaria da seguinte forma:

[TestClass]
public class CalculadoraDeFrete
{
    private TestChannel channel;

    [TestInitialize]
    public void Inicializar()
    {
        this.channel = new TestChannel();
        TelemetryConfiguration.Active.TelemetryChannel = channel;
    }

    [TestMethod]
    public void DeveCalcularFreteParaValinhos()
    {
        var cep = “13273-047”;
        var valorEsperado = 12.38M;

        var calculadora = new CalculadoraDeFrete();
        var resultado = calculadora.Calcular(cep);

        Assert.AreEqual(valorEsperado, resultado);

        var evento = this.channel.Itens.Single() as EventTelemetry;

        Assert.AreEqual(“CalculoDeFrete”, evento.Name);
        Assert.AreEqual(cep, evento.Properties[“Cep”]);
        Assert.AreEqual(resultado.ToString(), evento.Properties[“Resultado”]);
    }
}

ApplicationInsights – Utilizando a classe TelemetryClient

A Microsoft está disponibilizando um serviço de telemetria de aplicações chamado de Application Insights. É um serviço que roda no Azure (nuvem) e que permite integrar nas aplicações que desenvolvemos para que seja possível extrair informações, armazenar e, consequentemente, analisar os dados gerados para tentar identificar algum problema de performance ou de qualquer outra natureza.

Dependendo do tipo de aplicações onde este serviço é instalado, ele utiliza o recurso exposto pela aplicação para interceptar a requisição e catalogar as informações. Por exemplo, se este serviço é instalado em uma aplicação ASP.NET, então o módulo (IHttpModule) ApplicationInsightsHttpModule é incluído para interceptar as requisições que chegam à aplicação; já para aplicações ASP.NET 5, acopla-se através do método UseApplicationInsightsRequestTelemetry. Em ambos os casos, automaticamente o Application Insights começa a receber informações sobre as requisições que chegam para a aplicação, duração da requisição, cabeçalho, etc.

A identificação da aplicação para o serviço é uma chave chamada instrumentation key (GUID) que é gerada pelo Azure, e deve ser configurada na aplicação para que o Application Insights possa enviar ao serviço e ele, por sua vez, saiba qual aplicação está gerando os dados. E, novamente, dependendo da tecnologia, o arquivo utilizado para armazenar a chave é o ApplicationInsights.config para os projetos ASP.NET tradicionais ou aplicações Windows, e o config.json para o ASP.NET 5.

[ApplicationInsights.config]
<?xml version=”1.0″ encoding=”utf-8″?>
<ApplicationInsights>
  …
  <InstrumentationKey>bab34a9e-f1d9-4cf9-8a09-5f33b8f4ebed</InstrumentationKey>
</ApplicationInsights>

[config.json]
{
  “ApplicationInsights”: {
    “InstrumentationKey”: “bab34a9e-f1d9-4cf9-8a09-5f33b8f4ebed”
  },
  …
  }
}

Mesmo que ocorra essa mágica, o Application Insights fornece uma API que podemos recorrer para customizar os dados que são enviados para o serviço. Isso pode ser feito através da classe TelemetryClient, que expõe alguns métodos específicos ou de mais baixo nível para customizar diversas informações que podem ser levadas para o serviço. Para fazer uso desta classe, primeiramente precisamos utilizar o Nuget para adicionar o seguinte pacote:

Install-Package Microsoft.ApplicationInsights

É importante dizer que é possível fazer uso desta classe em projetos que não sejam do tipo ASP.NET. Como exemplo, vou utilizar uma aplicação Console para catalogar os mais diversos tipos de informações no Application Insights. No caso de projetos ASP.NET, já há uma opção durante a criação do projeto para habilita-lo, assim como é possível vermos na imagem abaixo, e a instalação explícita do pacote não é necessária.

>

Independente da forma como você adiciona o suporte para o Application Insights na aplicação, a classe TelemetryClient pode ser utilizada. Como já era de se esperar, esta classe fornece uma propriedade chamada InstrumentationKey, que é onde devemos configurar a chave gerado pelo Azure, mas em casos de projetos do tipo Windows, podemos criar o arquivo ApplicationInsights.config e lá ter o elemento InstrumentationKey, o que facilita a alteração sem precisar recompilar a aplicação.

var tc = new TelemetryClient()
{
    InstrumentationKey = “bab34a9e-f1d9-4cf9-8a09-5f33b8f4ebed”
};

A partir da instância da classe TelemetryClient criada, temos alguns métodos para enviar informações para o serviço. O Application Insights possui diversos tipos de informações (“categorias”) que possamos enviar os dados: Trace, Request, Page View, Expcetion, Dependency e Custom Event. Para cada uma destas informações, há um método correspondente: TrackTrace, TrackRequest, TrackPageView, TrackException, TrackDependency e TrackEvent.

Para exemplificar, considere o código abaixo. Estamos utilizando o método TrackEvent para indicar ao serviço que trata-se de um evento que vamos gerar diversas entradas e que corresponde à uma atividade de rotina da nossa aplicação. Além do nome, também podemos, opcionalmente, informar um dicionário de dados contendo propriedades que queremos anexar aquele evento. No exemplo, estou optando por incluir o parâmetro, o resultado e o tempo que levou para realizar o cálculo.

public class CalculadoraDeFrete
{
    private static TelemetryClient tc = new TelemetryClient()
    {
        InstrumentationKey = “bab34a9e-f1d9-4cf9-8a09-5f33b8f4ebed”
    };

    public static decimal Calcular(string cep)
    {
        var sw = Stopwatch.StartNew();

        //cálculo do frete
        var resultado = 12.38M;

        tc.TrackEvent(
            “CalculoDeFrete”,
            new Dictionary<string, string>()
            {
                { “Cep”, cep },
                { “Resultado”, resultado.ToString() },
                { “Tempo”, sw.Elapsed.ToString() }
            });
        tc.Flush();

        return resultado;
    }
}

Ainda em relação as propriedades que podemos anexar ao log no momento em que o evento ocorre, podemos também definir valores globais que serão enviados em todas as requisições, independentemente se está catalogando um evento, uma exceção, ou qualquer outra informação. E para isso, basta recorrer ao dicionário que está exposto através do contexto da classe TelemetryClient:

static CalculadoraDeFrete()
{
    tc.Context.Properties.Add(“Usuario”, “Israel Aece”);
}

Internamente a classe mantém um buffer com as entradas e periodicamente envia as requisições para o serviço. Utilizamos o método Flush para adiantar esse processo. Se consultarmos o portal, já podemos visualizar o evento adicionado e as respectivas propriedades que enviamos (incluindo a propriedade global Usuario). A partir deste nome do evento, eles sempre serão agrupados para uma melhor visualização e análise.

Como foi comentado acima, também é possível realizar o log de uma exceção. Para isso, podemos envolver o código inseguro em um bloco try/catch e utilizar o método TrackException. Estou optando por utilizar a versão mais simples do método, mas há parâmetros opcionais que permitem incluir um dicionário com valores customizados, assim como fizemos no código acima.

public static decimal Calcular(string cep)
{
    var resultado = 0M;

    try
    {
        throw new ArgumentException(“O CEP informado está fora da área de cobertura da transportadora.”);
        //cálculo do frete
    }
    catch (Exception e)
    {
        tc.TrackException(e);
        tc.Flush();
        throw;
    }

    return resultado;
}

Agora se atualizarmos o portal do Azure, irmos até a seção de Failures, o contador foi incrementado e é possível visualizar o erro que ocorreu, incluindo além da mensagem, toda a stack trace, útil para nós desenvolvedores, identificar onde o problema exatamente aconteceu.

Como é um exemplo simplista, estou fazendo o tratando localizado da exceção. Dependendo da estratégia de tratamento de erros da aplicação, é possível centralizar o envio das informações do erro em um ponto global, e dependendo da tecnologia utilizada, você pode recorrer ao suporte que ela dá para isso. Em aplicações ASP.NET tradicionais, você pode concentrar isso no evento Application_Error no arquivo Global.asax, no ASP.NET MVC em um filtro, no ASP.NET Web API no ExceptionLogger ou, no WCF, através da interface IErrorHandler.

Como podemos notar, o Application Insights eleva o “simples log de aplicações” para um outro nível. Podemos gerar diversas informações e temos a certeza que por trás existe uma grande infraestrutura para armazenamento e processamento delas. Terceirizando isso nos permite ainda mais focar no que de fato importa: o desenvolvimento da regra de negócio para qual a aplicação está sendo construída.

Composição de Tokens para Cancelamento

Ao contrário do que temos na classe Thread, a classe Task não fornece um método para abortar a execução da mesma. Se desejamos “monitorar” a execução e ter a chance de cancelar, temos que passar uma espécie de token ao criar a tarefa, e externamente, quando quisermos, podemos cancelar a execução. Compete aquele que programa a tarefa a ser executada, avaliar se o cancelamento foi ou não solicitado.

No .NET Framework a classe que nos permite controlar o cancelamento é a CancellationTokenSource. Ela expõe uma propriedade chamada Token que por sua vez, é representada pela classe CancellationToken, e é este valor que temos que passar para a tarefa a ser executada, e através do método Cancel podemos solicitar o cancelamento. Um detalhe importante aqui é que a classe CancellationTokenSource também disponibiliza um método estático chamado CreateLinkedTokenSource, que nos permite agrupar vários tokens, e quando qualquer um deles for cancelado, a tarefa é cancelada.

var cts1 = new CancellationTokenSource();
var cts2 = new CancellationTokenSource();

using (var cts3 = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token))
{
    var task = Task.Factory.StartNew(() =>
    {
        for (int i = 0; i < int.MaxValue; i++)
        {
            cts3.Token.ThrowIfCancellationRequested();
            Console.WriteLine(i);
        }
    }, cts3.Token);
               
    Console.ReadLine();
    cts2.Cancel();
    Console.ReadLine();
}

Repare que criamos dois tokens (cts1 e cts2) e agrupamos em um terceiro chamado cts3. Se invocarmos o método Cancel de qualquer um dos três, a tarefa será interrompida. Vale lembrar que somente o fato de passar o token na criação da tarefa não é suficiente para interromper a execução; como foi dito acima, é de responsabilidade do desenvolver monitorar a solicitação de cancelamento, e para isso, neste caso estamos utilizando o método ThrowIfCancellationRequested, que dispara uma exceção se a solicitação foi feita.

Por fim, note que apenas o terceiro CancellationTokenSource está sendo envolvido em um bloco using. Isso é porque quando criamos este objeto a partir do link entre outros, o método Dispose irá executar algumas atividades que irão impactar a memória, descartando objetos que são criados exclusivamente para isso. O método Dispose nesta classe também pode ser útil quando estamos utilizando a funcionalidade CancelAfter, que utiliza internamente um Timer para monitorar o tempo e, automaticamente, interromper a tarefa que está – ainda – sendo executada depois que o tempo expira. 

Criação e Gerenciamento de Conexões HTTP

Desde o início do .NET Framework temos uma classe chamada HttpWebRequest, que tem a finalidade de realizar requisições HTTP para algum recurso disponível. E como era de se esperar, ela expõe diversos métodos e propriedades para configurar as requisições que partem da instancia desta classe.

A cada requisição que é realizada, internamente ela recorre a classe ServicePointManager para criar a conexão até o recurso desejado, e a partir dai passa a reutilizar a mesma conexão nas chamadas subsequentes, poupando recursos da máquina de onde a requisição esta sendo feita. O objeto de conexão é criado considerando o protocolo, o host e a porta; se algum destes parâmetros variar, uma nova conexão é criada para atender este novo endereço e, consequentemente, reutilizada nas próximas requisições.

Só que existe a possibilidade de interferir na criação e gestão destas conexões. A classe HttpWebRequest define uma proprieade chamada ConnectionGroupName, e como o próprio nome sugere, ele considera o valor especificado nesta propriedade para criar a conexão, ou seja, para cada valor distinto definido nesta propriedade, uma nova conexão é criada. Se o valor se repetir, a conexão criada previamente é reutilizada.

Como sabemos, o WCF utiliza a classe HttpWebRequest nos bastidores quando acessa um serviço através do protocolo HTTP, e até então ele não disponibilizava qualquer propriedade no binding para configurar este pool de conexões HTTP. A partir da versão 4.6 do .NET Framework, a Microsoft permite ajustar este parâmetro (adicionando um prefixo) a fim de fazer uma melhor gestão e reuso das conexões HTTP pelos serviços WCF.

Por padrão, uma única conexão é mantida e compartilhada por todos os channels factories (proxy) que são instanciados pelo cliente. O que essa nova configuração irá fazer é criar uma conexão dedicada para cada channel factory criado pelo cliente, utilizando uma espécie de contador de instâncias para definir a propriedade ConnectionGroupName.

Para isso funcionar, basta ligar o flag useUniqueConnectionPoolPerFactory através do arquivo de configuração (app.config ou web.config) da aplicação cliente, assim como é mostrado no código abaixo.

<appSettings>
    <add key=”wcf:httpTransportBinding:useUniqueConnectionPoolPerFactory”
         value=”true” />
</appSettings>

Agora, se quiser um controle mais refinado e, de repente, variar a conexão de acordo com alguma regra ou parâmetro de negócio, você pode extrair e definir o nome do pool de conexões através das propriedades da mensagem do WCF, que em baixo nível, também vai utilizar o valor definido aqui para configurar a propriedade ConnectionGroupName.

OperationContext
    .Current
    .OutgoingMessageProperties
    .Add(“HttpTransportConnectionGroupNamePrefix”, “ValorCustomizado”);

Por fim, para ver isso em funcionamento, considere o código a seguir, que cria um laço e dentro dele instancia o channel factory e invoca o método do serviço. Antes de rodar, vamos configurar o flag como True para ver o impacto causado, provocando a criação de uma conexão dedicada para cada proxy. Por fim, é possível visualizar as conexões criadas através do utilitário TCPView.

var endereco = “http://localhost:9388&#8221;;

using (var host = new ServiceHost(typeof(Teste), new Uri(endereco)))
{
    host.AddServiceEndpoint(typeof(IServico), new BasicHttpBinding(), “”);
    host.Open();

    for (int i = 1; i < 11; i++)
        using (var srv = new ChannelFactory<IServico>(
            new BasicHttpBinding(), new EndpointAddress(endereco)))
                Console.WriteLine(srv.CreateChannel().Ping(“Teste ” + i.ToString()));
}

Propagando Transações

Como já sabemos, desde a versão 2.0 o .NET Framework possui uma API para criar e gerenciar transações dentro da aplicação. É o assembly System.Transactions.dll que disponibiliza um conjunto de APIs que podemos criar blocos transacionais, e assim alistar recursos que precisam de “proteção” para garantir que tudo seja efetivado ou desfeito caso algum problema ocorra (independente se o problema for de infraestrutura ou regra de negócio).

A principal classe que temos para isso é a TransactionScope, que ao ser envolvida em um bloco using, no método Dispose ela realiza o commit ou o rollback, dependendo se o método Complete foi ou não chamado. É dentro deste escopo criado que o .NET gerencia, e dependendo do que está envolvido nele, ele utiliza uma transação local (LTM) ou escala para uma transação distribuída (DTC).

Aqui estamos falando de um mesmo processo que é responsável por criar a transação, alistar os recursos, e por fim, finalizar a mesma (com sucesso ou falha). Mas como fazer quando a transação é iniciada pelo processo A e precisamos envolver as tarefas executadas por outro processo (B)? Ainda dentro deste mesmo assembly, temos uma classe chamada TransactionInterop, que expõe alguns métodos para “expandir” a transação entre processos.

Basicamente ele fornece métodos que geram uma chave e métodos que permitem recriar a transação a partir da mesma. Isso nos permitirá na aplicação A gerar a chave e importar na aplicação B, e com isso, ambas aplicações estarão envolvidas na mesma transação. É através do método estático GetTransmitterPropagationToken que geramos um array de bytes que representa o token de identificação da transação. Para exemplificar, vamos gerar este token a partir da aplicação A e armazenar este token um arquivo no disco para compartilhar com a aplicação B. No código abaixo estou removendo os logs para poupar espaço.

//Aplicação A
using (var ts = new TransactionScope())
{
    File.WriteAllBytes(@”C:TempTransactionToken.bin”,
        TransactionInterop.GetTransmitterPropagationToken(Transaction.Current));

    ts.Complete();
}

Do outro lado, utilizamos o método (também estático) GetTransactionFromTransmitterPropagationToken da classe TransactionInterop. Ele recebe como parâmetro um array de bytes (que estamos extraindo do arquivo) e recria a transação. Aqui o detalhe importante é reparar que o resultado deste método está sendo passado diretamente para um dos construtores da classe TransactionScope, que faz uso desta transação (criada pela outra aplicação) e envolve nela tudo o que está em seu próprio bloco using.

//Aplicação B
using (var ts =
    new TransactionScope(
        TransactionInterop.GetTransactionFromTransmitterPropagationToken(
            File.ReadAllBytes(@”C:TempTransactionToken.bin”))))
{
    ts.Complete();
}

Se repararmos as imagens abaixo, notamos que na a aplicação A possui o identificador de transação distribuída (DI) zerado, e quando a aplicação B se envolve na mesma transação, o identificador da transação distribuída na aplicação A reflete o mesmo identificador da aplicação B, ou seja, ambas aplicações estão envolvidas na mesma transação. Por fim, é possível ver na última imagem o log do DTC, indicando que a mesma foi promovida à uma transação distribuída.

Curiosidade: sabemos que o WCF fornece suporte à transações em serviços, podendo o cliente iniciar a mesma e o serviço participar. O id da transação viaja do cliente para o serviço através de headers do envelope SOAP, e quando o serviço recebe a informação, ele recria a transação utilizando os recursos (classes e métodos) que vimos neste artigo.

Validando XML com Schemas da NF-e

No post anterior comentei como configurar os certificados para realizar consultas nos serviços da NF-e. Naquele exemplo estamos montando o XML manualmente que corresponde ao corpo da mensagem enviada ao serviço. Montar o XML manualmente é uma tarefa complicada, já que estamos sujeito à erros de digitação e, consequentemente, o serviço irá rejeitar a requisição por não estar dentro do formato esperado.

Mas qual é esse formato? Felizmente temos schemas (arquivos XSD) que são fornecidos pelo governo para que possamos validar as mensagens localmente antes de fazermos a requisição. O .NET Framework já fornece classe nativas para tal validação, e tudo o que precisamos fazer, é submeter o XML (sendo um arquivo ou até mesmo uma string) para que a validação possa ser realizada.

É através da classe XmlReaderSettings que devemos configurar o arquivo XSD a ser utilizado e o namespace que será utilizado para varrer o XML e validá-lo. Apesar de informar apenas um arquivo XSD, internamente ele referencia outros schemas que o complementam, e é importante que eles existam fisicamente no mesmo local para que a validação possa ser realizada. 

Esta classe também fornece um evento chamado ValidationEventHandler, que podemos assinar e recebermos as notificações dos problemas que ocorrerem durante a validação. Com os argumentos deste evento, podemos extrair a severidade e mensagem do erro. O código abaixo ilustra a criação e configuração desta classe:

var config = new XmlReaderSettings()
{
    ValidationType = ValidationType.Schema
};

config.Schemas.Add(“http://www.portalfiscal.inf.br/nfe&#8221;, “consStatServ_v3.10.xsd”);
config.ValidationEventHandler += (s, e) =>
{
    Console.WriteLine(“{0}: {1}”, e.Severity, e.Message);
};

Depois dela devidamente configurada, informamos a mesma durante a criação do XmlReader. No exemplo abaixo, estou optando por validar o conteúdo XML que está em uma string, mas nada impede do conteúdo vir de um arquivo no disco.

var mensagem = “<?xml version=”1.0″ encoding=”utf-8″ ?>” +
            “<consStatServ xmlns=”http://www.portalfiscal.inf.br/nfe&#8221; versao=”3.10″>” +
            “<tpAmb>1</tpAmb>” +
            “<cUFx>35</cUFx>” +
            “<xServ>STATUS</xServ>” +
            “</consStatServ>”;

using (var reader = XmlReader.Create(new StringReader(mensagem), config))
    while (reader.Read()) { }

Propositalmente eu alterei o elemento cUF para cUFx, que é um elemento que não é suportado pelo XSD. Ao rodar a aplicação, a mensagem abaixo é exibida indicando o problema:

Error: The element ‘consStatServ’ in namespace ‘http://www.portalfiscal.inf.br/n
fe’ has invalid child element ‘cUFx’ in namespace ‘http://www.portalfiscal.inf.b
r/nfe’. List of possible elements expected: ‘cUF’ in namespace ‘http://www.porta
lfiscal.inf.br/nfe’.

Validando a Assinatura Digital da NF-e

Atualmente as empresas emitem as notas fiscais em formato eletrônico. Para isso, foi desenvolvido um projeto que especifica e rege a emissão destas notas em ambiente nacional, que é conhecido como Nota Fiscal Eletrônica ou, simplesmente, NF-e. Este projeto faz uso de diversas tecnologias para garantir a segurança e, principalmente, a integridade da mesma.

A integridade é a garantia de que o arquivo XML que a representa não tenha sido alterado desde a sua emissão. Quando uma empresa emite uma nota fiscal, a SEFAZ gera um arquivo XML digitalmente assinado, utilizando o certificado digital da empresa emitente. Como sabemos, esse arquivo XML é a nota fiscal em formato eletrônico, e essa assinatura está embutida nele. A assinatura digital nada mais é que um cálculo matemático que é realizado sobre todo o arquivo XML, e se qualquer mudança ocorrer neste depois da assinatura, a mesma se tornará inválida.

Se você recebe este arquivo e quer garantir que ele não tenha sido alterado, então podemos recorrer à classes que estão dentro do .NET Framework para realizar esta validação. Basicamente devemos carregar o conteúdo XML para o objeto XmlDocument, e em seguida, procurar pelo elemento <Signature /> que é armazena o hash calculado e o certificado serializado que foi utilizado para realizar a assinatura.

var xml = new XmlDocument();
xml.Load(“00000000000000000000000000000000000000000000.xml”);

var nfe = (XmlElement)xml.GetElementsByTagName(“NFe”)[0];
var signature = (XmlElement)nfe.GetElementsByTagName(“Signature”)[0];
var signer = new SignedXml();

signer.LoadXml(signature);
Console.WriteLine(signer.CheckSignature());

Depois de carregado e separado os elementos que serão avaliados, recorrermos a classe SignedXml para validar a assinatura, onde devemos submeter o elemento que contém a assinatura para o método LoadXml, e em seguida, invocar o método CheckSignature, que retorna um valor boleano indicando se ela está ou não válida.

O overload do método CheckSignature utilizado acima (sem parâmetros) analisa o elemento <Signature /> tentando extrair os certificados de forma automática. Caso queira ter um maior controle sobre os certificados utilizados para analisar a assinatura, podemos utilizar um código mais rebuscado para atingir este objetivo:

private static bool ValidateWithCertificate(SignedXml signer)
{
    var keyInfoEnumerator = signer.KeyInfo.GetEnumerator();

    while (keyInfoEnumerator.MoveNext())
    {
        var x509Data = keyInfoEnumerator.Current as KeyInfoX509Data;

        if (x509Data != null && x509Data.Certificates.Count > 0)
            foreach (var cert in x509Data.Certificates)
                if (signer.CheckSignature((X509Certificate2)cert, true))
                    return true;
    }

    return false;
}

Como o próprio nome sugere, a propriedade KeyInfo contém informações referentes à chave que foi utilizada para realizar a assinatura. E, utilizando um enumerador, identificamos se trata-se de um certificado, e ao iterar pela coleção, invocamos o método CheckSignature, e através de um segundo overload, passamos o certificado que queremos que ele considere para realizer a validação. Apesar de ter o mesmo resultado, aqui é possível extrair informações do certificado utilizado, caso seja necessário.

Importante: um erro bastante comum é que alguns sistemas incluem novas informações no XML depois que ele foi assinado. Ao fazer isso, a assinatura digital é corrompida, e ao submetermos o XML para o código que escrevemos acima, a assinatura será dada como inválida. Entre essas informações, é comum ver namespaces como os que são mostrados abaixo (em negrito), e segundo a Nota Técnica 2010/009 da SEFAZ, eles não devem ser incluídos, nem antes, e muito menos depois, da assinatura.

<?xml version=”1.0″ encoding=”UTF-8″?>
<nfeProc xmlns=”http://www.portalfiscal.inf.br/nfe&#8221;
         xmlns:ds=”http://www.w3.org/2000/09/xmldsig#&#8221;
         xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;

         versao=”2.00″>
  <NFe xmlns=”http://www.portalfiscal.inf.br/nfe”&gt;
    <infNFe Id=”NFe…” versao=”2.00″>

Hospedando o ASP.NET Web API no OWIN

Há algum tempo a comunidade criou uma especificação chamada OWIN (Open Web Interface for .NET), que convencionou uma camada de abstração entre os servidores web (por exemplo, o IIS) e os frameworks para desenvolvimento de aplicações Web, desacoplando um do outro e assim facilitando a portabilidade de aplicações entre os mais diversos modelos de servidores web e/ou sistemas operacionais, bem como a fácil criação e integração de novos componentes que não devem ser dependentes do servidor web onde eles estão sendo executados.

Com este modelo já bem difundido, a Microsoft criou um projeto chamado Katana, que nada mais é que uma implementação desta especificação. Até pouco tempo atrás, os projetos ASP.NET dependiam da biblioteca System.Web.dll (parte do .NET Framework), e que esta possuia forte dependência do IIS, fazendo com que as aplicações ASP.NET serem, obrigatoriamente, hospedadas lá. Aos poucos, os projetos ASP.NET (MVC, Web API, SignalR, etc.) foram se “livrando” da dependência desta DLL, possibilitando assim que estes projetos sejam construídos e levados para serem executados em qualquer ambiente.

Para fazer uso do OWIN em conjunto com o ASP.NET Web API é bem simples graças a sua estrutura enxuta e simplista, que combinado com algumas estensões (do C#), resume a configuração em poucas linhas de código e, consequentemente, já torna a aplicação independente do hosting onde ela está sendo executada. O primeiro passo para criar uma aplicação console (self-hosting) capaz de hospedar uma Web API é instalar o pacote, via Nuget, chamado Microsoft.AspNet.WebApi.OwinSelfHost. Ao instalar, várias DLLs são baixadas e podemos visualizar isso através das referências que foram realizadas no projeto.

O ponto de entrada para a configuração é a criação de uma classe com um método público chamado Configuration, que recebe como parâmetro um objeto que implemente a interface IAppBuilder (OWIN), e via Reflection, ele será acessado pelo runtime. É no interior deste método que faremos a configuração necessária para que as APIs Web funcionem, e como sabemos, toda a configuração para o ASP.NET Web API é concentrada na classe HttpConfiguration. Depois de devidamente configurado, devemos recorrer ao método Use[XXX], exposto através da interface IAppBuilder, que adiciona um componente (conhecido como middleware) no pipeline para execução.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();

        config.Routes.MapHttpRoute(“Default”, “{controller}”);

        app.UseWebApi(config);
    }
}

Depois da classe de configuração criada, temos que recorrer à classe estática WebApp que através do método Start, recebe como parâmetro genérico o tipo da classe que servirá como responsável pela configuração e pelo pipeline de execução, e também temos que informar a URL em que a Web API ficará disponível/acessível.

using (WebApp.Start<Startup>(“http://localhost:8080&#8221;))
{
    Console.WriteLine(“Iniciado”);
    Console.ReadLine();
}

E como vimos na imagem acima, dentro deste projeto também temos uma classe chamada ClientesController (que herda de ApiController) que contém os métodos que recebem e retornam clientes, e quando acessado por alguma aplicação, o resultado é devolvido conforme esperamos, sem qualquer diferença quando comparado à hospedagem no IIS.