Utilizando Microsoft Azure Service Bus com REST e Xamarin

O Azure Service Bus nada mais é do que um barramento entre aplicações distribuídas que controla, de forma segura e escalável, a troca de informações (mensagens) entre elas. Podemos considerar como suas principais funções:

  • roteamento de mensagens;
  • tradução de mensagens;
  • tradução de protocolos.

Um exemplo de Service Bus é o roteamento de mensagens para os serviços de push notification da Apple, Google e da própria Microsoft. Para utilizar estes sistemas, já existem bibliotecas, como a Azure Messaging. Porem uma limitação desse, é o fato de estar preso ao sistema de push notification.

Como não existe nenhuma biblioteca de como usar o Service Bus com Xamarin sem ser para os serviços citados acima, nos que resta a opção de enviar por REST. No exemplo abaixo, enviaremos nosso posicionamento GPS para o Service Bus (para ler mais sobre como ler a posição GPS no Android clique aqui).

Criando o Service Bus

O primeiro passo é criar o Service Bus dentro do portal do Azure. Após acessar o portal, procure e clique na opção Service Bus como aparece abaixo.
Criando Service Bus

Vamos precisar da chave de acesso para enviar o posicionamento para o Service Bus. Clique em "Settings" > "Shared Access policies" > "RootManageSharedAccessKey", conforme imagem abaixo. Certifique-se de que as opções a direita estejam de acordo com o sinalizado em vermelho.
Pegando a chave de acesso

Criando projeto no Xamarin Studio

Vamos usar o Xamarin Studio para criar o nosso projeto Xamarin.Android.
Clique em "Files" > "New Project", selecione "Android App" e clique em "Next".
Criando Xamarin.Android usando Xamarin Studio

Vamos iniciar criando uma nova classe chamada "EnviarParaServiceBus.cs"

using System;  
namespace ArtigoServiceBus  
{
    public class EnviarParaServiceBus
    {
        public EnviarParaServiceBus()
        {
        }
    }
}

Inclua dentro do public class EnviarParaServiceBus { }:

        static string token;
        const string sbHostName = "https://artigoservicebus.servicebus.windows.net/";
        const string SASKey = "kxGk2Gc835dtYVDinOboXlyFHictrfAnMFSMjn/dG3A=";

private static string GetSASToken(string SASKeyName, string SASKeyValue)  
        {
            var fromEpochStart = DateTime.UtcNow - new DateTime(1970, 1, 1);
            var expiry = Convert.ToString((int)fromEpochStart.TotalSeconds + 3600);
            var stringToSign = WebUtility.UrlEncode(sbHostName) + "\n" + expiry;
            using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(SASKeyValue)))
            {
                var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
                var sasToken = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
                    WebUtility.UrlEncode(sbHostName), WebUtility.UrlEncode(signature), expiry, SASKeyName);
                return sasToken;
            }
        }

Dica: Altere no sbHostName = "https://artigoservicebus.servicebus.windows.net/" a parte sinalizada para o nome que você deu ao serviço dentro do Azure.

Dica2: Altere o SASKey para o que foi criado no "RootManageSharedAccessKey".

O próximo passo é criar a função que envia os dados para o Queue do Service Bus. O Queue é o local onde os dados ficam até que outro serviço ou aplicação processe as informações.

Para o envio das mensagens para o Service Bus recomendo o RestSharp.

Nuget

No projeto clique em "Packages" > "Add Packages" e procure por RestSharp.
RestSharp

Enviando os dados

Na classe "EnviarParaServiceBus.cs" vamos incluir as funções:

private static bool CreateQueue(string queueName)  
        {
            var queueAddress = sbHostName + queueName;
            var restClient = new RestClient(queueAddress);
            var putData = @"<entry xmlns=""http://www.w3.org/2005/Atom"">
                          <title type=""text"">" + queueName + @"</title>
                          <content type=""application/xml"">
                            <QueueDescription xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"" xmlns=""http://schemas.microsoft.com/netservices/2010/10/servicebus/connect"" />
                          </content>
                        </entry>";

            var request = new RestRequest(Method.PUT);
            request.AddHeader("Authorization", token);
            request.RequestFormat = DataFormat.Xml;
            request.AddParameter("text/xml;charset=utf-8", putData, ParameterType.RequestBody);

            var response = restClient.Execute(request);         
            if ((response.StatusCode == HttpStatusCode.OK) || (response.StatusCode == HttpStatusCode.Created))
            {
                return true;
            }

            return false;
        }

        private static bool SendMessage(string queueName, string body)
        {
            var fullAddress = sbHostName + queueName + "/messages" + "?timeout=60&api-version=2013-08 ";
            var client = new RestClient(sbHostName + queueName);

            var request = new RestRequest("/messages" + "?timeout=60&api-version=2013-08 ", Method.POST);
            // easily add HTTP Headers
            request.AddHeader("Authorization", token);

            request.AddParameter("application/json; charset=utf-8", body, ParameterType.RequestBody);
            request.RequestFormat = DataFormat.Json;
            try
            {
                var response = client.Execute(request);
                if ((response.StatusCode == HttpStatusCode.OK) || (response.StatusCode == HttpStatusCode.Created))
                {
                    return true;
                }
                else if (response.StatusCode == HttpStatusCode.NotFound)
                {
// Caso o Queue não exista, cria e envia a mensagem novamente
                    var retorno = CreateQueue(queueName);
                    if (retorno)
                        SendMessage(queueName, body);
                }
            }
            catch (Exception ex)
            {
                var Error = ex.Message;
            }

            return false;
        }

No "MainActivity.cs" vamos alterar a chamada do button.Click para:

button.Click += delegate { 

                var Retorno = EnviarParaServiceBus.SendToServiceBus("ArtiugoServiceBus", "{posicao: 1234.56, 0987.65}");
                if (Retorno)
                {
                    button.Text = "Envio efetuado com sucesso";
                }
                else
                {
                    button.Text = "Erro ao enviar dados para o Service Bus";
                }
            };

Após executar o exemplo acima, vamos acessar o painel de controle do Azure e ver que um Queue foi criado e existe uma mensagem a ser processada.

Queue Criado Mensagem Enviada

Com isso, conseguimos enviar mensagens simples ou complexas para a retaguarda sem precisarmos acessar um WebApi conectado a base, por exemplo. Retiramos assim a carga do servidor de aplicação e processando a informação sob demanda.

Dúvidas? Idéias?

Marco A. Ghostman

Empreendedor desde os 18 anos, sócio da MASS Labs, empresa de tecnologia, hoje, voltada para o mercado de mobilidade urbana. Desenvolvedor .NET com expertise em aplicações móveis.

Florianópolis/SC