Xamarin Forms with Microsoft Azure

Xamarin Forms with Microsoft Azure

xamarinformsazure1

Short introduction

Mobile apps – mostly all of them are connected with some services. Retrieving data, receiving notifications or saving data. There are many options to create backend for mobile apps including Xamarin. This is great that nowadays Xamarin developers are on Microsoft stack so we have one developer platform:

  • Cloud – Microsoft Azure
  • Mobile – Xamarin

That’s why I decided to write this article and show you how to connect Xamarin Forms application and Azure cloud serivce. Before we start I would like to present components we will use in this sample:

  • Azure Blob Storage – place where you can store files – like pictures in our case
  • Azure DocumentDB – no SQL database where you can store objects in JSON format
  • Azure Function – servless code architecture where you can process events – in our case HTTP requests

Steps we will do in this article:

  • Create Xamarin Forms app to take photos with title and description added
  • Azure Function with HTTP Post trigger to retrieve data sent from the mobile app
  • Azure DocumentDB to store photo as JSON
  • Azure Blob Storage to store photo as BLOB object with metadata

THIS SAMPLE IS TO PRESENT DIFFERENT CAPABILITIES OF AZURE AND XAMARIN

 

What do I need to start?

1) Visual Studio 2015 Community (for free) or higher

2) Microsoft Azure subscription (you can test it for free here)

 

Let’s start

1. Sign in to Microsoft Azure portal here:

xamarinformsazure2

 

Create Azure Blob Storage

1. Click on the “plus” button on the left and search for “blob” and select “Storage account” from the list:

xamarinformsazure3

2. Click “Create” button and below window should appear with information to fill:

Type the unique “Name” and set the rest like below. Then click “Create” button:

xamarinformsazure4_4 xamarinformsazure5

3. After few seconds storage account should be ready:

xamarinformsazure6

Before we go further it is worth to mention how blob storage structure looks like:

blob1

  • Storage Account: All access to Azure Storage is done through a storage account. This storage account can be a General-purpose storage account or a Blob storage account which is specialized for storing objects/blobs. For more information about storage accounts, see Azure storage account.
  • Container: A container provides a grouping of a set of blobs. All blobs must be in a container. An account can contain an unlimited number of containers. A container can store an unlimited number of blobs. Note that the container name must be lowercase.
  • Blob: A file of any type and size. Azure Storage offers three types of blobs: block blobs, page blobs, and append blobs.
    • Block blobs are ideal for storing text or binary files, such as documents and media files – we will use this type to store our photos
    • Append blobs are similar to block blobs in that they are made up of blocks, but they are optimized for append operations, so they are useful for logging scenarios
    • Page blobs can be up to 1 TB in size, and are more efficient for frequent read/write operations

4. It is time to add container:

xamarinformsazure7

5. Type the name of your container – remember that it has to be lowecase and set access type to “private”. Then click “Create” button:

xamarinformsazure8

6.After few seconds container should be created and shown on the list:

xamarinformsazure9

That’s it! We will create blobs during uploading photos later in this article.

Remember to copy storage key and storage name – we will use them later in this article:

xamarinformsazure10

 

Create Azure DocumentDB

1. Click “Plus” button on the left and search for “documentDB”. Then select “NoSQL (DocumentDB)” and click “Create” button:

xamarinformsazure11

2. Fill all required information like below. Remember to select unique URL and resource group created before (when created Azure Storage above). Then click “Create” button:

xamarinformsazure12

3. After few seconds you should see that DocumentDB was created:

xamarinformsazure13

Before we move forward it is good to describe what is the structure of data in DocumentDB:

json-database-resources1

  • A database account consists of a set of databases, each containing multiple collections
  • Collections can contain stored procedures, triggers, UDFs, documents, and related attachments
  •  A database also has associated users, each with a set of permissions to access various other collections

 

4. Click “Add Collection” button:

xamarinformsazure14

5. Type the name of your collection. In my case this is “PhotoMetaData”. Remember also to provide database id:

Storage capacity should be set to 10GB – it is just for demo purpose.

Click “OK” button:

xamarinformsazure15

After few seconds database with collection should be created.

6. Go to “Document Explorer” (available from the list on the left). There you should review your documents in the different collections and databases:

xamarinformsazure16

That’s it! Now we have DocumentDB ready.

Remember to copy database and collection name and also Uri and Primary Key – we will use them later:

xamarinformsazure17

 

Create Azure Function

1. Click on the “plus” button on the left and search for “function” and select “Function App” from the list. Then click “Create” button:

xamarinformsazure18

2. Fill all required information. Remember to use previously created resource group. Click “Create” button:

xamarinformsazure19_9

3. After few seconds function should be ready:

xamarinformsazure20

 

It is time to connect this Azure components! : )

We would like to take picture with our Xamarin Forms application and then save it with metadata (title and description). Let’s start from configuring our Azure Function.

1. Click “New Function” tab and select “API & Webhoks” scenario. Then select “HttpTrigger-CSharp” template:

xamarinformsazure21

xamarinformsazure22_2

2. Type the name of your function and set “Authorization level” to “Function”. Then click “Create” button:

xamarinformsazure23

3. After few seconds function is ready for development:

xamarinformsazure24

4. Go to “Integrate” tab:

xamarinformsazure25

5. Select “Triggers” tab:

xamarinformsazure26

We would like to limit our HTTP trigger to POST method (to send photos to Azure). Configuration is shown below:

xamarinformsazure27

Click “Save” button.

6. Now go to “Outputs” and select “HTTP”:

xamarinformsazure28

Save below configuration:

xamarinformsazure29

Configure function app settings

Now it is time to configure function app settings like Storage and DocumentDB connections.

1. Select “Function app settings” from left list:

xamarinformsazure30

2. Select “”Configure app settings”:

xamarinformsazure31

3. Now we need to add configuration keys:

  • PhotoStorage – connection string to photos storage – it should look like this: DefaultEndpointsProtocol=https;AccountName=storagesample;AccountKey=<account-key>
  • PhotoDbUrl – Url to your DocumentDB database
  • PhotoDbPrimaryKey – Primary key for your DocumentDB
  • PhotosDbName – name of your database in DocumentDB
  • PhotosCollectionName – name of your collection in DocumentDB
  • PhotoContainer – name of  your container in PhotoStorage

xamarinformsazure32_3

Save changes.

4. Return to “Develop” tab to see Function code:

xamarinformsazure24

 

Connect Azure Function with Azure Blob Storage

Below code with description is responsible for receiving http request with JSON that contains Photo object which consists of:

  • Title (string)
  • Description (string)
  • FileName (string)
  • File (byte array)

 

// For framework assemblies, add references by using the #r "AssemblyName" directive:
// Read more here: https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-csharp#referencing-external-assemblies

#r "Microsoft.WindowsAzure.Storage"
#r "Newtonsoft.Json"

// Add standard using statements:

using System.Net;
using System.Text;
using System.Configuration;
using Microsoft.Azure; // Namespace for CloudConfigurationManager
using Microsoft.WindowsAzure.Storage; // Namespace for CloudStorageAccount
using Microsoft.WindowsAzure.Storage.Blob; // Namespace for Blob storage types
using Newtonsoft.Json; // Namespace for JSON .NET
using Newtonsoft.Json.Serialization; // Namespace for JSON .NET


public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");


    // Get request body:
    dynamic data = await req.Content.ReadAsAsync<object>();

    // Get data as string:
    var stringData = data.ToString();

    // Log that there is data:
    log.Info("Got stringData: " + stringData);

   // Convert photo from JSON:
    var photo = JsonConvert.DeserializeObject<Photo>(stringData);

    // Log photo title:
    log.Info("Got photo with title: " + photo.Title);

    // Upload photo file to Azure Blob Storage using AddFileToBlobStorage method (placed below in code):
    AddFileToBlobStorage(photo);

    // Log that file was successfully uploaded:
    log.Info("Photo successfully stored in Blob");

   // Return succcess status code:
    return req.CreateResponse(HttpStatusCode.OK, "Completed");
}

private static void AddFileToBlobStorage(Photo newPhoto)
{
    // Retrieve storage account from connection string:
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["PhotoStorage"]);

    // Create the blob client:
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

    // Retrieve reference to a previously created container:
    CloudBlobContainer container = blobClient.GetContainerReference(ConfigurationManager.AppSettings["PhotoContainer"]);
    container.CreateIfNotExists();

    // Retrieve reference to a blob named like your file:
    CloudBlockBlob blockBlob = container.GetBlockBlobReference(newPhoto.FileName);

    // Add photo title:
     blockBlob.Metadata.Add("Title", newPhoto.Title);

    // Add photo description:
    blockBlob.Metadata.Add("Description", newPhoto.Description);

    // Create blob with taken photo:
    blockBlob.UploadFromByteArray(newPhoto.File, 0, newPhoto.File.Length);
}

// Photo class used to describe uploaded photo:
public class Photo
    {
        public string Title { get; set; }
        public string Description { get; set; }
        public string FileName { get; set; }
        public byte[] File { get; set; }
    }

Great – now you know how to use Azure Function to receive HTTP requests, process them and then uplad files to Azure Blob Storage.

 

Connect Azure Function with DocumentDB

While configuration for Azure Blob Storage is ready we can pin our Function with DocumentDB database. Below you can find extended code with description to access to DocumentDB:

1. First of all we need to add DocumentDB NuGet package. Open right tab and click “Add” button on top:

xamarinformsazure33

2. Add file called “project.json”:

xamarinformsazure34

File should contains below code:

{
  "frameworks": {
    "net46":{
      "dependencies": {
       "Microsoft.Azure.DocumentDB": "1.12.0"
      }
    }
   }
}

2. Get back to “Run.csx” file and paste below function code:

xamarinformsazure35

We extended existing code with “UploadDocument” method:

// For framework assemblies, add references by using the #r "AssemblyName" directive:
// Read more here: https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-csharp#referencing-external-assemblies

#r "Microsoft.WindowsAzure.Storage"
#r "Newtonsoft.Json"

// Add standard using statements:

using System.Net;
using System.Text;
using System.Configuration;
using Microsoft.Azure; // Namespace for CloudConfigurationManager
using Microsoft.WindowsAzure.Storage; // Namespace for CloudStorageAccount
using Microsoft.WindowsAzure.Storage.Blob; // Namespace for Blob storage types
using Newtonsoft.Json; // Namespace for JSON .NET
using Newtonsoft.Json.Serialization; // Namespace for JSON .NET
using Microsoft.Azure.Documents.Client; // Namespace for DocumentDB


public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");


    // Get request body:
    dynamic data = await req.Content.ReadAsAsync<object>();

    // Get data as string:
    var stringData = data.ToString();

    // Log that there is data:
    log.Info("Got stringData: " + stringData);

   // Convert photo from JSON:
    var photo = JsonConvert.DeserializeObject<Photo>(stringData);

    // Log photo title:
    log.Info("Got photo with title: " + photo.Title);

    // Upload photo file to Azure Blob Storage using AddFileToBlobStorage method (placed below in code):
    AddFileToBlobStorage(photo);

    // Log that file was successfully uploaded:
    log.Info("Photo successfully stored in Blob");

    // Add photo to DocumentDB:
    UploadDocument(photo);

    // Log that file was successfully uploaded:
    log.Info("Photo successfully stored in DocumentDB");


   // Return succcess status code:
    return req.CreateResponse(HttpStatusCode.OK, "Completed");
}

private static void AddFileToBlobStorage(Photo newPhoto)
{
    // Retrieve storage account from connection string:
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["PhotoStorage"]);

    // Create the blob client:
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

    // Retrieve reference to a previously created container:
    CloudBlobContainer container = blobClient.GetContainerReference(ConfigurationManager.AppSettings["PhotoContainer"]);
    container.CreateIfNotExists();

    // Retrieve reference to a blob named like your file:
    CloudBlockBlob blockBlob = container.GetBlockBlobReference(newPhoto.FileName);

    // Add photo title:
     blockBlob.Metadata.Add("Title", newPhoto.Title);

    // Add photo description:
    blockBlob.Metadata.Add("Description", newPhoto.Description);

    // Create blob with taken photo:
    blockBlob.UploadFromByteArray(newPhoto.File, 0, newPhoto.FileName.Length);
}

public static void UploadDocument(Photo newPhoto)
{
    var documentClient = new DocumentClient(new Uri(ConfigurationManager.AppSettings["PhotosDbUrl"]), ConfigurationManager.AppSettings["PhotoDbPrimaryKey"]);
    documentClient.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(ConfigurationManager.AppSettings["PhotosDbName"], ConfigurationManager.AppSettings["PhotosCollectionName"]), newPhoto);
}

// Photo class used to describe uploaded photo:
public class Photo
    {
        public string Title { get; set; }
        public string Description { get; set; }
        public string FileName { get; set; }
        public byte[] File { get; set; }
    }

Great – now you know how to use Azure Function to receive HTTP requests, process them and then save them as document in DocumentDB database.

 

Create Xamarin Forms photo app

1. Create new Xamarin Forms app using below project template in Visual Studio:

xamarinformsazure36

2. We will use Android, UWP and iOS projects and of course Portable to share the code:

xamarinformsazure37

3. Open “MainPage.xaml” file from “Portable” project and paste below XAML code:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:XamarinFormsPhotoApp" x:Class="XamarinFormsPhotoApp.MainPage">

  <ContentPage.Content>
    <Grid>
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
      </Grid.RowDefinitions>
      
      <Image x:Name="PhotoImage" Grid.Row="0" Margin="24" HorizontalOptions="Center"/>
      <ActivityIndicator x:Name="PhotoActivityIndicator" Grid.Row="1" Margin="24" IsVisible="false"/>
      <Entry x:Name="TitleEntry" Grid.Row="2" Placeholder="Photo title..." Margin="24"/>
      <Entry x:Name="DescriptionEntry" Grid.Row="3" Placeholder="Photo description..." Margin="24"/>
      <Button x:Name="AddPhotoButton" Grid.Row="4" Text="Select picture" Margin="24" <span class="pl-e">Clicked</span>=<span class="pl-s"><span class="pl-pds">"</span>Handle_Click<span class="pl-pds">"</span></span>/>
      
    </Grid>
  </ContentPage.Content>

</ContentPage>

4. Now it is time to add “Xam.Plugin.Media” NuGet to each project:

xamarinformsazure38

Then add “Microsoft.Net.Http” NuGet to Portable project:

xamarinformsazure40

5. Add folder called “Model” in Portable project and class “Photo” inside it:

xamarinformsazure39

 public class Photo
    {
        public string Title { get; set; }
        public string Description { get; set; }
        public string FileName { get; set; }
        public byte[] File { get; set; }
    }

6. Replace code in “MainPage.xaml.cs” file with the one below (with description included):

  public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        // Method responsible for selecting image from gallery:
        private async Task<MediaFile> GetPhoto()
        {
            // Check if access is supported:
            if (CrossMedia.Current.IsPickPhotoSupported)
            {
                // Get image and return it:
                var image = await CrossMedia.Current.PickPhotoAsync();
                return image;
            }
            return null;
        }
        // Method responsible for displaying image in UI:
        private void DisplayImage(MediaFile image)
        {
            // Display selected image from gallery in UI:
            PhotoImage.Source = ImageSource.FromStream(() =>
            {
                return image.GetStream();
            });
        }

        // Method responsible for creating new Photo object:
        private Photo CreatePhoto(MediaFile image)
        {
            using (var memoryStream = new MemoryStream())
            {
                image.GetStream().CopyTo(memoryStream);
                var imageByteArray = memoryStream.ToArray();
                var photo = new Photo()
                {
                    Title = TitleEntry.Text,
                    Description = DescriptionEntry.Text,
                    FileName = Path.GetFileName(image.Path),
                    File = imageByteArray
                };
                return photo;
            }
        }
        // Method where we call Azure Function:
        private async Task SendRequest(Photo photo)
        {
            HttpClient httpClient = new HttpClient();
            var serializedPhoto = JsonConvert.SerializeObject(photo);
            var content = new StringContent(serializedPhoto, Encoding.UTF8, "application/json");
            // Remember to paste below your Azure Function Key copied before in the Portal:
            httpClient.DefaultRequestHeaders.Add("x-functions-key", "AZURE_FUNCTION_KEY_HERE");
            var httpResponse = await httpClient.PostAsync("https://xamarinphotosdemofunction.azurewebsites.net/api/Photo-trigger", content);
        }

        // Invoke above methods when user clicks button:
        private async Task CallAzureFunction()
        {
            var image = await GetPhoto();
            var photo = CreatePhoto(image);
            DisplayImage(image);
            ShowActivityIndicator(true);
            await SendRequest(photo);
            ShowActivityIndicator(false);

        }

        // Hide or show ActivityIndicator control on UI thread:
        private void ShowActivityIndicator(bool show)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                PhotoActivityIndicator.IsVisible = show;
                PhotoActivityIndicator.IsRunning = show;
            });
        }

        //Button click event handler:
        async void Handle_Click(object sender, EventArgs e)
        {
            await CallAzureFunction();
        }
    }

Before you launch the app, remember to add permissions:

1. Android manifest:

  <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

2. iOS info.plist:

  <key>NSPhotoLibraryUsageDescription</key>
  <string>Photo Library Access Required</string>

3. UWP manifest – Pictures library capability

 

Launch application and see result

  • Type title
  • Type description
  • Select image from the gallery

 

Android:

xamarinformsazure41

iOS

xamarinformsazure42

UWP

xamarinformsazure43

 

Sum up

As you can see with Microsoft Azure you are able to implement various scenarios. Now you know that you do not need to have own server – you can use Azure Function. What’s more you know how to connect it with your Xamarin Forms application to store data in Azure Blob and DocumentDB. This is only the beginning – you should definitely try different services. Enjoy!

 

Advertisements