Além dos Tipos Primitivos

Ao criar tipos customizados para a aplicação, é comum utilizarmos os tipos primitivos da linguagem (inteiro, data, decimal, etc.) para especificar os campos que ele deverá conter, podendo trabalhar internamente ou externamente com estas informações. Se não nos atentarmos no momento da criação, é capaz de inflarmos o novo tipo com uma porção de propriedades, que muitas vezes podem estar relacionadas, e prejudicando assim a interface exposta para os consumidores.

Além disso, podemos perder parte do encapsulamento, pois se deixarmos para o consumidor combinar os campos para testar uma condição, pode ser que em algum momento ele se esqueça de avaliar de forma correta e, consequentemente, ter um resultado inesperado. Para exemplificar, considere a classe abaixo:

tipos1

Note que as propriedades estão divididas nas cores vermelha e azul. As propriedades em vermelho dizem a respeito do vencimento do boleto, enquanto as propriedade em azul se referem ao valor do título. O valor a ser pago pelo título é o valor bruto deduzindo o abatimento e o desconto (desde que esteja sendo pago antes da data limite para o mesmo). Já o vencimento agrupa tudo o que é necessário para indicar a real data de pagamento e/ou a quantidade de dias que falta para vencer ou que está vencido.

Se o consumidor quiser saber a data real de vencimento terá que fazer esta análise; se ele quiser saber o valor real do pagamento (deduzindo os descontos), terá que calcular. E o pior, isso deverá ser replicado para todos os pontos da aplicação que precisar disso. Uma solução seria criar propriedades de somente leitura na classe Boleto e já retornar os valores calculados. Só que fazendo isso, voltamos ao problema inicial: comprometer a interface pública do tipo. Mesmo que estivermos confortáveis em prejudicar a interface, pode ter outros tipos dentro do nosso domínio que precisa também lidar com isso (uma nota promissória, por exemplo, também tem vencimento), e tornamos a recriar tudo isso lá.

Para centralizar as regras, padronizar o consumo e reutilizar quando necessário, o ideal é abrir mão dos tipos primitivos e passar a criar tipos específicos para o nosso domínio, que agrupe os campos e forneça os dados já calculados, para que seja possível o consumo unificado das informações.

tipos2

Depois disso, a nossa classe Boleto fica bem mais enxuta, e a medida que vamos se aprofundando nas propriedades, chegamos nos mesmos dados, dando mais legibilidade e tendo a mesma riqueza de informações que tínhamos antes.

public class Boleto
{
    public Vencimento Vencimento { get; set; }
    public Valor Valor { get; set; }
}

var boleto = new Boleto()
{
    Vencimento = DateTime.Now.AddDays(5),
    Valor = 1250.29M
};

Note que se ajustarmos os operadores (overloading), conseguimos converter tipos primitivos em tipos customizados, conforme é possível ver acima, e tornar ainda mais sucinto o código.

Por fim, os ORMs que temos hoje permitem a serialização de todo o tipo ou de parte dele. Fica a nosso critério o que armazenar, ou seja, se optamos apenas pelos dados que originam o restante ou se armazenamos tudo o que temos, mas não é uma decisão fácil de tomar. Se optar por armazenar tudo, você ocupará mais espaço em disco; em contrapartida, se guardar apenas os dados que originam o restante e utilizar algum outro mecanismo para extração dos mesmo (DAL) sem passar pelo domínio, você não conseguirá reconstruir algumas informações sem replicar a regra na sua camada de leitura.

Desenvolvimento de UIs

Por mais simples e fina que ela seja, uma das partes mais importantes de um sistema deskop, web ou mobile, é a interface gráfica. Por mais complexo e tecnológico que seja as camadas mais baixas da aplicação, independentemente dos padrões de arquitetura e projeto que utilize, se é uma base de dados relacional ou No-SQL, etc., é a interface com o usuário que receberá a maior parte das interações e é ela que inicialmente é apresentada quando se propõe ou vendo uma solução.

Além da interface ser a principal responsável por capturar informações e devolver respostas (de sucesso ou falha), é ela também quem exibe os dados para que os usuários realizem a análise gerencial e operacional da empresa para qual o sistema foi desenvolvido.

Apesar de existir uma porção de artigos e documentações que descrevem boas práticas para a construção de interfaces, o bom entendimento do negócio garantirá aos desenvolvedores a criação e otimização de telas para que em pouco espaço, sejamos capazes de apresentar poucos dados, mas com muitas informações.

A ideia é repensar a forma como as construímos, tendo em mente a atividade (ou tarefa) que o usuário irá desempenhar naquela tela. Entender a essência do problema é crucial para o sucesso da criação das telas, e o usuário que é o responsável por executar a tal atividade dentro da empresa é a melhor pessoa com quem se pode falar para extrair as dificuldades/exigências. Em seguida, temos que tentar abstrair tudo de importante que foi colhido, e por fim, implementar.

Abaixo estão algumas técnicas que utilizamos na construção de aplicações para a empresa em que trabalho. A ideia aqui é exibir alguns conceitos, dificuldades e soluções que foram encontradas e implementadas. Apesar dos exemplos serem aplicações desktop (WPF) e web, eles não se limitam a estes cenários; nada impede de utilizar estes conceitos na construção de um aplicativo móvel.

Observação: clique nas imagens para visualiza-las em um tamanho maior.

Dashboards

Todos os funcionários da empresa têm atividades diárias. Algumas pessoas estão condicionadas a executar sempre as mesmas tarefas, analisar os mesmos dados. Se conseguirmos mapear tudo o que ele deve olhar e monitorar, podemos criar um painel que concentra todas as informações que coordenarão o seu dia.

Bem-vindo aos dashboards. Assim como o painel de um carro, que centraliza todas as informações relevantes para a condução e monitoramento do mesmo, os dashboards em uma aplicação tem o mesmo sentido. Se começar a setorizar a sua empresa, irá perceber que cada departamento terá ações distintas (muitas vezes, sobre os mesmos dados), e antes dele sair analisando um a um para saber se há problemas, porque já não apontar as divergências para que ele resolva?

Além disso, os dashboards muitas vezes exibem informações e índices sobre a saúde de algum recurso da empresa, sobre dados financeiros, etc., para que pessoas de nível gerencial possam acompanhar e tomar as decisões cabíveis para cada situação. Reportar periodicamente tais informações garante que ele possa reagir assim que detecta algo suspeito.

Análises

Além dos dashboards que dão uma visão mais panorâmica sobre certos aspectos, há telas que podem concentrar informações mais detalhadas a respeito de algo ou alguém. Por exemplo, qual o risco atual do cliente XYZ? Qual a posição do meu estoque?

Quando colocamos várias informações lado a lado, temos que de alguma forma evidenciar algumas delas, separando muitas vezes por severidade. Existem índices que servem como histórico, enquanto outros indicam a quantidade e total de títulos vencidos que a empresa possui. Saber diferenciar entre essas duas informações garantirá o sucesso da tela, pois é com essa segmentação do que é ou não crítico que vamos utilizar para desenhar e destinar os espaços necessários para cada seção.

O tamanho da fonte é um importante aliado no momento em que precisamos destacar certos valores. A parte superior da tela sempre me pareceu o primeiro ponto em que olhamos quando a mesma é aberta. E aproveitando este instinto, podemos concentrar em uma linha horizontal as informações mais críticas do cliente, enquanto o restante da tela exibe informações de menor severidade, mas não tão menos importantes.

É claro que isso não é uma regra. Você pode optar por utilizar o canto direito, canto esquerdo, etc., para concentrar informações de análise acerca do que está olhando naquele momento. Abaixo está um outro cenário, agora web, que apresenta a situação atual de uma empresa na mesma tela em que exibe os seus títulos em aberto e algumas outras informações de histórico.

Por fim, é importante dizer que nada é estático. A maioria dos índices podem ser (e na maioria das vezes serão) clicáveis. O que quero dizer é que ao clicar no total de vencidos, será apresentado uma tela contendo os títulos que compõem aquele valor.

Repare que essa forma muda como o usuário pensa. Algumas vezes, tudo o que o usuário quer saber é quanto a empresa XYZ está devendo; não importa quantos títulos são. Em geral, o que se apresenta é uma tela contendo vários tipos de filtros, onde um deles é o código/CNPJ da empresa em questão, que ao clicar em filtrar, os 4822 títulos são listados.

Neste outro modelo proposto, basta ele chegar até a empresa e já terá uma sumarização, as pendências não concluídas, sendo possível apontar os títulos que estão vencidos (que ele precisa atuar).

Cores

O tamanho da fonte não é o seu único aliado no momento de destacar informações. As cores também podem representar muita coisa. Além do verde (positivo), vermelho (negativo), azul (indiferente) e amarelo (alerta), podemos abusar das mais diversas cores para indicar algum comportamento, evolução ou tendência de alguma informação.

As cores não se restringem apenas aos índices. Você pode optar por colorir diversas partes do sistema, como por exemplo, o contorno de uma janela que exibe a nota daquele cliente. Repare que a nota, o número propriamente dito, começa a ser irrelevante, já que todo o contexto gráfico indica que aquele é um cliente ruim, independente da escala utilizada (1 a 5, 1 a 10, 10 a 100, etc.).

Gráficos

Gráficos são recursos que cabem na maioria das aplicações. O importante é sempre ter um bom componente à mão para que seja fácil a criação, já que gráficos podem ser criados aos montes, cruzando diversos tipos de informações.

O maior desafio não é a parte técnica, mas sim as informações que compõem o gráfico. Com o conhecimento do negócio é possível que você sugira algumas opções predefinidas, mas é o usuário, com o conhecimento e experiência, que pode indicar quais os melhores gráficos para enriquecer a aplicação.

Sempre há uma discussão em torno disso, que é: criar manualmente cada gráfico ou disponibilizar os dados para que alguma ferramenta externa (Excel, Power BI, etc.)? É uma decisão difícil, pois a construção de gráficos é estática, ou seja, se quiser um novo gráfico, precisamos criar uma nova tela, extrair os dados e exibir, compilar e redistribuir, ao contrário dessas ferramentas específicas, que recebem um conjunto de dados e você molda como preferir.

Ao meu ver, a vantagem de ter o gráfico dentro da aplicação é a possibilidade de inserir o mesmo em um contexto específico, como por exemplo, colocar lado a lado com outras informações que estão sendo analisadas no momento da aprovação de alguma operação.

Contexto

Informações de contexto são sempre bem-vindas quando está analisando ou tomando alguma decisão. São informações que estão conectadas de alguma forma com o que está sendo analisado, e não estou me referindo à banco de dados aqui. Situações onde você está avaliando o crédito para uma empresa e vê que ela está devendo R$ 200.000,00 no mercado, e com apenas um clique, você consegue chegar rapidamente a lista de credores e seus respectivos valores.

Elas podem estar na mesma tela de análise, mas mesmo que haja espaço suficiente para ela, sacar a informação de algum outro lugar pode ser mais interessante, pois evita o risco de poluir demasiadamente a tela. Temos que ponderar entre a discrição e a facilidade de acesso à informação. Considere o exemplo abaixo, onde há uma operação de crédito sendo analisada, qual já possui diversos parâmetros, mas se o usuário desejar, pode acessar as últimas operações realizadas para definir a taxa que será aplicada à operação corrente. A janela que aparece é apenas uma tooltip.

Interação

Nem sempre as aplicações têm uma área de ajuda, pois não é algo fácil de fazer e, principalmente, de manter. Muitas vezes ela nunca é utilizada, pois é mais fácil ligar para alguém e perguntar sobre a dificuldade em fazer alguma atividade dentro do sistema.

Ao invés de criar uma área de ajuda, que concentra 100% das informações e detalhamento de como utilizar seções do sistema, a forma mais simples e intuitiva seria espalhar pelas telas da aplicação informações que ajudem o usuário a esclarecer possíveis dúvidas que ele tenha no momento da realização de uma determinada tarefa.

Repare que com poucas palavras é possível esclarecer um termo que à primeira vista parece ser complexo e confunde o usuário na escolha. A mesma regra pode se aplicada na descrição de um link que ele pode estar na dúvida em qual deles escolher:

Feedback

Reportar falha de execução de alguma atividade (seja de infraestrutura ou de negócio) é fácil, pois basta indicar o motivo do erro e pedir para o usuário tentar novamente. Mas o grande desafio é notificar, de forma simples e objetiva, a conclusão da mesma.

Não estou falando aqui de “cadastro realizado com sucesso”, “operação enviada para análise”, etc., mas sim de exibir detalhes precisos da atividade que o usuário acabou de realizar. Quando você dá entrada em algum órgão, é comum eles darem um protocolo indicando o número, a data, o prazo de conclusão, o nome, etc. Poderíamos utilizar a mesma regra aqui, ou seja, quando a atividade for concluída, podemos exibir na tela detalhes que o deixem seguro de que a mesma foi executada com sucesso.

É claro que isso nem sempre é possível ou viável. Processos simples também demandam mensagens mais simples. Mas considere mesmo estes casos simples para ser mais esclarecedor com o usuário, indicando com mais ênfase o que acabou de ser realizado. Opte por “A empresa teve a sua razão social alterada de Israel Aece-ME para Israel Aece Ltda.” ao invés de “Alteração realizada com sucesso.”.

Foco em Tarefas

No nível mais baixo, sabemos que tudo o que um sistema faz em uma base de dados é inserir, atualizar, excluir e ler os dados(CRUD). Só que se ficarmos preso a este modelo de trabalho, vamos construir telas que simplesmente farão estas quatro operações básicas, orientando elas a serem voltadas para a estrutura do nosso banco de dados.

Só que as telas podem dizer muita coisa sobre o comportamento e as atividades que devemos fazer com os dados, que nem sempre se referem à apenas uma única entidade. Muitas vezes a atividade é composta de diversas outras subatividades, que contribuem para a totalidade de uma tarefa a ser executada.

Imagine que você tem um cliente e ele está bloqueado de operar. A implementação mais trivial possível no banco de dados é ter uma tabela chamada “Cliente” com um flag chamado “Bloqueado”. Como seria a construção da tela que desbloqueia o cliente?

Geralmente temos um formulário que você edita todos os dados, e nele está incluído um checkbox que está associado à coluna “Bloqueado”. Ao clicar no botão atualizar, os dados são persistidos na base de dados e o cliente está apto a operar novamente. Mas essencialmente será que o desbloqueio seria apenas isso? Será que o desbloqueio não seria algo muito maior, que depende que alguém solicite e outra pessoa seja responsável por analisar o motivo e autorizar o não o desbloqueio? Será que não precisamos de histórico de alteração? Qual a justificativa para o desbloqueio? Qual a razão de aceitar o desbloqueio?

Isso é um exemplo de uma tarefa que você executa contra o seu cliente, ou seja, solicitar o seu desbloqueio. Não é um simples formulário de edição. Se você pensar orientando à tarefas que podem ser executadas naquela entidade, é provável que nem precise de um formulário para isso. Aos poucos você começa a perceber que as telas da aplicação desencadeiam ações.

Suas telas deixam de serem formulários baseados na base de dados. Elas possam a ser desenhadas de acordo com a atividade que aquele usuário deve desempenhar. Se ele é responsável por aprovar a alteração de vencimento de boletos, então podemos relacionar os que estão atualmente na sua alçada e permitir com que ele possa selecionar os que deseja aprovar e escolher a opção de conclusão.

Relatórios

É uma tentação por parte dos usuários. Sempre quando eles querem visualizar alguma massa de dados, eles falam em “relatórios”. Para mim, relatório é o que se imprime, ou seja, aquilo que se manda para a impressora. Mesmo que relatórios sejam indispensáveis para aplicações, não quer dizer que eles devem ser utilizados como forma de exibir um conjunto de dados em tela.

Algumas aplicações, por questões de simplicidade, utilizam relatórios para exibição, por exemplo: listar todos os títulos vencidos do Israel, clientes com divergências cadastrais, empresas localizadas em São Paulo, etc. Apesar de isso ser possível, torna a relação estática, ou seja, não é possível clicar no cliente que está sem endereço e ajustar. Teria que imprimir, abrir a tela de cadastro de clientes, localizar o mesmo, e em seguida, fazer a alteração.

Como provavelmente existe uma pessoa responsável pelo cadastro dos clientes, então no dashboard dela poderia existir um índice que indica a quantidade de clientes com divergências, e ao clicar, uma tela seria apresentada com esta relação; bastaria dar um clique e já ajustar o endereço e ao sair, a relação já seria sensibilizada e o cliente recém alterado iria desaparecer. As telas tem um grande poder, pois pequenas sumarizações servem também de filtro para uma listagem, sem a necessidade de ter um formulário de pesquisa para isso.

Outro ponto importante a ser considerado é segurança. A impressão de relatórios permite com que algum funcionário mal-intencionado imprima e entregue a relação de clientes para um concorrente. Não que com a tela seja impossível de acontecer, mas chama mais atenção alguém fotografando a tela do computador.

Os relatórios precisam ser pensados com cautela, pois como disse acima, é uma tentação para os usuários. É importante entender a essência do problema, focando na atividade que vem após a impressão. Isso nos dará a oportunidade de construir uma tela que atenda a necessidade deles sem a impressão física da relação de dados.

E claro, não há como escapar de desenvolver relatórios. E sem querer se contraditório, eles são sempre bem-vindos.

A ideia deste artigo foi apenas mostrar algumas técnicas que utilizamos no desenvolvimento das aplicações para empresa onde trabalho. Não há nenhuma regra que deve ser assegurada aqui. São apenas experiências que foram vivenciadas e que a escolha, no meu ambiente, se fez válida. Use como quiser.

Performance com Server Push

No post anterior eu comentei sobre os benefícios da utilização do server push, recurso que foi disponibilizado a partir do HTTP/2. Lá mencionei sobre a melhor reutilização da conexão TCP quando ela é estabelecida para extrair algum recurso que desejamos solicitar, como por exemplo, uma página HTML.

É comum qualquer página HTML depender de recursos extras, tais como arquivos de scripts, estilos (CSS) e imagens. Considere o exemplo abaixo, que é uma página extremamente simples que referencia cinco arquivos de estilos.

<html>
    <head>
        <link href=”Estilos1.css” rel=”stylesheet” type=”text/css” />
        <link href=”Estilos2.css” rel=”stylesheet” type=”text/css” />
        <link href=”Estilos3.css” rel=”stylesheet” type=”text/css” />
        <link href=”Estilos4.css” rel=”stylesheet” type=”text/css” />
        <link href=”Estilos5.css” rel=”stylesheet” type=”text/css” />
    </head>
    <body>
        Testando
    </body>
</htm>

Quando fazemos a requisição para esta página HTML, é possível notar no log abaixo uma barra cinza em cada linha de acesso para os arquivos *.css. Essa cor indica o período de tempo em que o navegador fica aguardando para iniciar a requisição para o respectivo recurso. É importante notar que neste exemplo estamos utilizando o HTTP 1.1.

Já agora se fizermos a requisição utilizando o HTTP/2, podemos perceber que não existe mais a barra cinza, ou seja, isso indica que os recursos são carregados de forma concorrente, sem a necessidade de ter um delay. Isso tudo é possível perceber na imagem abaixo.

Server Push no HTTP/2

Quando fazemos a solicitação para alguma página de um site, além de seu próprio conteúdo, ela referencia alguns outros recursos (tais como arquivos de scripts, imagens, estilos (CSS), etc.), e para cada um destes itens, novas requisições partem do navegador do cliente para baixa-los e, finalmente, apresentar o resultado final do usuário que a solicitou.

Na maioria das vezes estes recursos extras estão debaixo do mesmo servidor, e como sabemos, os navegadores limitam o número máximo de conexões simultâneas para um determinado domínio, o que gera certa lentidão no acesso, pois dependendo do tamanho e tempo de download destes arquivos, o resultado levará ainda mais tempo para ser exibido.

Como alternativa, é comum utilizarmos uma técnica conhecida domain-sharding, que nos permite espalhar os recursos extras por diferentes domínios e permitir o download simultâneo de todos eles; a outra opção é utilizar scripts ou estilos inline, que evita round-trips extras, mas acaba dificultando a manutenção e reutilização de código, e ainda, perdemos a opção de realizar caching destes recursos do lado do cliente.

Entre os novos recursos que o HTTP/2 fornece, um deles é o server push, que nos permite otimizar os problemas descritos acima, fornecendo uma opção que viabiliza o uso de referências externas sem comprometer a performance. A versão HTTP/2 faz um melhor uso das conexões TCP, e devido a restruturação de como a mensagem é enviada e recebida, passa a ser possível utilizar uma mesma conexão para requisitar e receber o resultado da solicitação e também dos recursos por ela utilizados e que não solicitados explicitamente.

Quando o servidor entende que o recurso solicitado faz uso de outras referências, ele é capaz de empurrar ao cliente essas referências indicando que elas serão utilizadas no futuro; na sequência ele devolve o resultado (HTML) da página e quando o navegador percebe que há imagens, CSS ou scripts, antes dele fazer a requisição para cada um deles, ele percebe que os mesmos já foram entregues, evitando o round-trip para cada um destes recursos extras, diminuindo consideravelmente o tempo de exibição do conteúdo como um todo.

Apesar de que isso não afete em nada as aplicações que já estão rodando ou que serão desenvolvidas, é importante saber da existência e comportamento desta funcionalidade para tirar proveito destas novas funcionalidades de mais baixo nível. Com o Windows 10, Internet Information Services (IIS) e o Edge, é possível ver isso em funcionamento. É importante mencionar que, por enquanto, a Microsoft apenas implementou este recurso apenas quando o site está sendo acessado através de HTTPS. É possível visualizar o HTTP/2 sendo usado através do log do Edge. E claro, se o cliente não suportar o HTTP/2, ele utilizará o HTTP 1.1 como fallback.

Recursos da Palestra do MVC Summit 2012

 

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.

SingleWSDL no WCF

Como o WCF é fortemente baseado em SOAP, ele fornece várias funcionalidades para lidar com os documentos WSDL, que são documentos que descrevem as funcionalidades e os tipos de dados utilizados por um determinado serviço. Com este arquivo, podemos referenciá-lo nas aplicações clientes, para que elas possam construir toda a infraestrutura necessária (proxy) para realizar a comunicação.

Só que o documento WSDL gerado pelo WCF contém em seu interior, os detalhes referente as funcionalidades que são expostas pelo serviço. Já as operações podem receber e/ou retornar vários tipos de dados, que devem também estar contemplados no documento. Só que ao invés disso, toda a estrutura dos tipos utilizada pelas operações do serviço, é colocada em arquivos externos (XSD), e o WSDL apenas os referencia.

Ao consumir estes tipos de documentos dentro do próprio .NET, não há problemas, pois ele consegue facilmente importar o documento WSDL e resolver essas dependências. O problema começa a aparecer quando consumimos este WSDL em outras tecnologias, que exigem que todas as definições do serviço estejam dentro de um mesmo arquivo, não lidando com essa modularização. Por estas questões de interoperabilidade, temos que recorrer à algumas implementações customizadas para gerar o WSDL neste formato. Uma das opções mais conhecidas é o FlatWSDL, criada pelo Christian Weyer, já há algum tempo.

Já na versão 4.5 do WCF, a Microsoft já trará isso nativamente, ou seja, a criação do serviço continua a mesma, só que podemos acessar o endereço que expõe o WSDL, anexando na querystring o sufixo ?singleWsdl, o que fará com que o documento WSDL gerado, incluia toda a informação necessária, sem referências para arquivos externos. Abaixo temos uma imagem quando acessamos este serviço no navegador. Note que há um link na página que já aponta para este novo recurso.

Recursos da Palestra do TechEd Brasil 2011

Ontem eu fiz uma palestra no TechEd Brasil 2011, e o principal assunto abordado lá foi a nova API que a Microsoft está criando para facilitar a construção, hospedagem e consumo de serviços WCF baseados em REST.

O exemplo principal foi concetrado um projeto que nomeie de Techitter, que é composto por algumas aplicações simulando – de muito longe – o Twitter. A solução é composta por 4 projetos, onde um é o serviço, e onde concentra-se grande parte das novidades, um site em ASP.NET MVC que via jQuery posta e carrega as mensagens; outro projeto que consome a mesma API como um widget e, finalmente, uma aplicação WPF que também faz uso do serviço, consumindo o mesmo serviço via HttpClient, que também compõe a nova API. Para incrementar, existe o consumo de um serviço criado em outra tecnologia (NodeJs.exe), que foi consumido pelo serviço.

Gostaria de agradecer a todos os presentes, e também ao Rogerio Cordeiro pela oportunidade. Para aqueles interessados, o download do projeto pode ser baixado clicando aqui.