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.
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.
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".
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.
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.
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?