Back-End

21 ago, 2018

Xamarin Forms e Azure Cosmos DB

Publicidade

Não é incomum nossas aplicações trabalharem com armazenamento de dados. No mundo mobile, além de criarmos um banco de dados “temporário” localmente nos dispositivos – utilizando desde soluções SQL como SQLITE e até soluções No SQL, como o LITE DB – também criamos uma API que irá receber os dados mais importantes e sensíveis da aplicação.

Vale ressaltar que, por motivos de segurança, principalmente no mundo mobile, não é recomendado que as aplicações se conectem diretamente com o banco de dados master para salvar/consultar informações. Como nós já sabemos, as conexões mobile sofrem com uma qualidade não tão boa quanto desejada, ficando a mercê de 3Gs e alcance WiFi.

O que é o Cosmos DB

Cosmos DB é um serviço de banco de dados multi modelo e distribuído globalmente. É um serviço desenvolvido pela Microsoft e está disponível no Azure.

Apesar de ser um banco de dados não relacional e baseado em documentos, ele possui diversas linguagens de manipulação como o próprio SQL. O Cosmos DB possui SDKs para integração com .NET, Java, JavaScript, Phyton, C++, Gremlin, GO e Xamarin.

Você pode ver alguns quick starts neste endereço.

Porque usar o Cosmos DB?

O Cosmos DB oferece algumas vantagens bastante interessantes para nossas aplicações, como:

  • Escalabilidade global: imagine que você criou um banco de dados para sua aplicação no Brasil e com o decorrer do tempo percebe que sua aplicação passou a ser utilizada também por pessoas que moram no Estados Unidos. Sem problemas, com alguns cliques você consegue replicar a sua base dados para um datacenter do Azure no Estados Unidos e os usuário de lá passarão a utilizar este banco da dados, diminuindo a latência do serviço.
  • Segurança: toda comunicação do Cosmos DB é feita em cima de HTTPS. Suas informações são criptografadas ao sair da sua aplicação até chegarem ao servidor, e vice versa. É comum termos problemas de conexão no mundo mobile, como citei acima. A comunicação do Cosmos DB é executada com um three-way Handshake, ou seja, o pacote sai da sua aplicação, chega ao Cosmos DB, que por sua vez envia uma confirmação de recebimento para aplicação e então a aplicação envia uma confirmação do recebimento deste pacote de confirmação para o Cosmos DB.
  • RestFull APIs: todas as iterações são feitas com o protocolo HTTP. Você pode utilizar todos os recursos do protocolo como, por exemplo, os Status Code na resposta de cada requisição.

Além destes pontos citados acima, o custo do Cosmos também é bem interessante, sendo R$ 0,83 centavos por giga de armazenamento mensais.

Como posso manipular os dados salvos no Cosmos DB?

Como eu citei acima, ele possui SDKs de integração com .NET, Java, JavaScript, Phyton, C++, Gremlin, GO e Xamarin. Além disso, você pode acessar o portal do Azure e utilizar a linguagem escolhida por você no momento da criação para manipular os dados, além de ser possível utilizar também o Azure Storage Explorer.

Na criação do seu banco de dados Cosmos DB você poderá optar por algumas APIs de manipulação de dados. Atualmente as disponíveis, são:

  • SQL API
  • MongoDB API
  • Cassandra API
  • Graph API
  • Table API

Você pode escolher a que você possui maior familiaridade para utilizar na manipulação dos documentos salvos no seu banco de dados.

Criando o banco de dados no Cosmos DB

Acesse o portal do Azure e selecione a opção Azure Cosmos DB e então clique em “+ Add“.

Preencha as informações solicitadas e selecione a API de manipulação de dados de sua preferência na caixa de seleção API e clique em “Create“. Neste exemplo, vou trabalhar com a opção de API SQL.

Após ser finalizado o deploy do Azure Cosmos DB, ele estará disponível na sua conta no resource group selecionado.

Escalabilidade global

Acessando o menu Replicate data globally você irá visualizar a região do data center que selecionou na criação e os demais que estão disponíveis para replicação global do banco de dados. Lembre-se que cada replicação implicará em aumento de custos, então só faça em caso de necessidade.

Chaves para somente leitura e para leitura e escrita

Acessando o menu Keys você visualizará as chaves de acesso para o banco de dados. Por padrão o Cosmos DB já possui duas chaves de acesso, um com diretos apenas de leitura e outra para leitura e escrita.

Cada unidade de armazenamento de dados no Cosmos DB é uma Collection. Dentro das collections, serão armazenados nossos documentos que conterão nossos dados.

Clicando na opção “Settings“, você terá acesso ao painel de criação e gerenciamento das collections. Clicando na opção “New Collection” você poderá criar uma nova collection. Clicando na opção “New SQL Query” você poderá utilizar a linguagem SQL para consultar os dados da sua collection.

Xamarin Forms + Cosmos DB

A integração entre Xamarin e o Cosmos DB é bastante simples, dado que a ferramenta já disponibiliza um SDK para integração.

Nos passos a seguir vou falar sobre a integração entre o app e o Cosmos DB. Para não alongar muito o artigo não vou falar sobre as configurações do projeto para ViewModels, como PropertyChanged e Bindings. Você poderá ver isso no código fonte do artigo que está no GitHub, disponível no link no final do artigo.

Após criado o Cosmos DB e a collection no portal do Azure, já podemos iniciar a integração entre o app e o serviço de banco de dados. Para isso, vamos iniciar instalando o SDK para .NET.

Instale o pacote do NuGet Microsoft.Azure.DocumentDB.Core no PCL e em todas as plataformas.

Install-Package Microsoft.Azure.DocumentDB.Core

Usando as keys de leitura e escrita e apenas leitura

Vamos criar uma classe estática para armazenar nossas keys e também a URL do nosso serviço Cosmos DB criados anteriormente no portal do Azure:

public static class DocumentDbConstants
{
    public static readonly string ReadWritePrimaryKey = "Sua chave de leitura e escrita gerada no azure";
    public static readonly string ReadOnlyPrimaryKey = "Sua chave somente leitura gerada no azure";
 
    public static readonly string Url = "url do Cosmos DB gerado no azure";
}

Criando uma tela de listagem de dados

Após criada a classe que irá conter nossas constantes, vamos criar uma tela de lista para exibir os registros salvos no Cosmos DB.

<ContentPage.ToolbarItems>
     <ToolbarItem Text="Add" Command="{Binding AddClubCmd}"/>
 </ContentPage.ToolbarItems>
 <ContentPage.Content>
     <StackLayout>
         <ListView ItemsSource="{Binding Clubs}" HasUnevenRows="True">
             <ListView.ItemTemplate>
                 <DataTemplate>
                     <ViewCell>
                         <StackLayout HeightRequest="60" Padding="10">
                             <Label Text="{Binding Name}" FontSize="16" FontAttributes="Bold"/>
                             <Label Text="{Binding Country}"/>
                         </StackLayout>
                     </ViewCell>
                 </DataTemplate>
             </ListView.ItemTemplate>
         </ListView>
     </StackLayout>

Vamos também criar uma ViewModel para essa tela que irá realizar a consulta de dados no Cosmos DB, chamada ClubListViewModel.

Na ViewModel vamos criar um objeto do tipo DocumentClient, que estará disponível após a importação da biblioteca Microsoft.Azure.Documents.Client do SDK, chamado client. Através deste objeto faremos as iterações com o Cosmos DB.

Vamos também criar uma propriedade do tipo URI, chamada collectionLink, que irá apontar para nossa unidade de dados e para a Collection do Cosmos DB no Azure, recebendo o valor gerado pelo o método CreateDocumentCollectionUri do classe UriFactory do SDK.

private DocumentClient client; 
private Uri collectionLink = UriFactory.CreateDocumentCollectionUri(@"SampleCosmos", @"Clubs");

Onde SampleCosmos é o nome da unidade de armazenamento de dados e Clubs é o nome da collection.

Vamos instanciar nosso client no método construtor da ViewModel e utilizar as constantes definidas na classe DocumentDbConstants criada acima:

client = new DocumentClient(new System.Uri(DocumentDbConstants.Url), DocumentDbConstants.ReadOnlyPrimaryKey);

Observe que, como o intuito desta página é apenas listar dados, além da URL do Cosmos DB, vamos informar a chave de apenas leitura para nosso client.

Além disso, teremos também uma lista para receber os dados. Um command irá chamar o método que realizará a consulta no Cosmos DB.

Consultado dados no Cosmos DB

O método abaixo irá consultar todos os registros da collection no Cosmos DB. Observe que vamos utilizar a collectionLink que foi definida na ViewModel.

public async Task GetAll()
{
    try
    {
        var query = client.CreateDocumentQuery<Club>(collectionLink, new FeedOptions { MaxItemCount = -1 })
              .AsDocumentQuery();
        while (query.HasMoreResults)
        {
            Clubs.AddRange(await query.ExecuteNextAsync<Club>());
        }
    }
    catch (Exception e)
    {
        Console.Error.WriteLine(@"ERROR {0}", e.Message);
    }
     
}

Criando a tela de inserção de dados

Vamos adicionar uma nova página que deve ser exibida quando o usuário clicar no menu “add” da barra de titulo da tela de lista:

<StackLayout>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
 
        <Label Text="Club Name: " Grid.Column="0" Grid.Row="0"/>
     
        <Entry Placeholder="Club Name" Text="{Binding NewClub.Name}" Grid.Column="1" Grid.Row="0"/>
 
        <Label Text="Country: " Grid.Column="0" Grid.Row="1"/>
 
        <Entry Placeholder="Country" Text="{Binding NewClub.Country}" Grid.Column="1" Grid.Row="1"/>
 
    </Grid>
    <Button Text="Save" Command="{Binding SaveCmd}"/>
</StackLayout>

Assim como na ViewModel da página de lista, nesta página também vamos adicionar os objetos client e collectionLink.

Você pode isolar essas operações em um Service de forma genérica para que centralize as comunicações com o Cosmos DB no service. Para efeitos didáticos manterei na ViewModel.

Nesta ViewModel, como o objetivo é inserir dados, vamos informar para o client além da URL do Cosmos DB, a chave de leitura e escrita no Cosmos DB que está armazenado na classe DocumentDbConstants, veja abaixo:

client = new DocumentClient(new System.Uri(DocumentDbConstants.Url), DocumentDbConstants.ReadWritePrimaryKey);

Inserindo dados no Cosmos DB

O método abaixo irá inserir dados no Cosmos DB. Observe que a comunicação entre app e Cosmos DB será realizada em cima do protocolo HTTPS, sendo possível checar o StatusCode da requisição. Isso é importante pois assim temos a certeza de que o banco de dados recebeu o comando por completo, prevenindo assim, que o banco fique corrompido por problemas de conexão do smartphone que está executando a app.

Para garantir que o pacote foi recebido com sucesso e integrado pelo Cosmos DB, ocorre um troca de pacotes de confirmação automática entre app e Cosmos DB. Assim que o Cosmos DB recebe o pacote, ele emite uma mensagem de confirmação para o app que, ao receber este pacote, envia outro confirmando o recebimento do anterior.

public async Task InsertItemAsync(Club club)
{
    try
    {
        club.Id = Guid.NewGuid().ToString();
 
        var result = await client.CreateDocumentAsync(collectionLink, club);
 
        if(result.StatusCode == System.Net.HttpStatusCode.OK)
            await App.Current.MainPage.Navigation.PushAsync(new Views.ClubList());
         
    }
    catch (Exception e)
    {
        Console.Error.WriteLine(@"ERROR {0}", e.Message);
    }
}

No método acima checamos se o StatusCode recebido é o 200 do protocolo HTTP, e se for, redirecionamos para página de lista.

Com base no StatusCode, poderíamos tomar diferentes ações para cada código de resposta do HTTP, como 400, 401, 500 entre outros.

Conclusão

Como podemos ver no decorrer do artigo, o Cosmos DB possui muitos recursos para nossas aplicações, desde chaves de segurança com níveis de permissões distintos, à escalabilidade global geo posicional, e até mesmo a possibilidade de trabalhar com SQL sendo um banco de dados não relacional.

Não é possivel dizer que com o Cosmos DB você não precisará mais de uma API no seu app. Sabemos que cada aplicação possui cenários diferentes de complexidade. Entretanto, se o seu cenário for apenas de CRUD simples, acredito que o Cosmos DB poderá de te ajudar bastante reduzindo a necessidade de uma API para integração com app.

E ai, o que você acha? Concorda? Já fez algo com o Cosmos DB?

Você pode efetuar o download do código fonte do artigo no meu GitHub clicando aqui.

***

Este artigo foi produzido em parceria com a Lambda3. Leia outros conteúdos no blog da empresa: blog.lambda3.com.br