Header Ads

Android MAUI.NET8: Integrate Authorize Azure Function HTTP API with SQLite & Secure Storage

Serverless RESTful APIs are gaining popularity day by day simply because of it severless nature and by the fact that coding these APIs have never been simpler. Azure Functions have changed the way REST web APIs are developed. Traditionally, RESTful API requires thoughtful planning especially for the infrastructure selections upon which these APIs will be developed along with the hustle of deployment configurations and security considerations. Most of these traditional infrastructures have been eliminated into a simple severless RESTful APIs structure where main goal is to focus on the business logic of RESTful web APIs. These serveless RESTful APIs now truly articulating the service-base architecture behavior and are easily integrated with any client platform that supports the RESTful APIs.

The word serverless is not truly serverless, meaning a cloud server is still needed for deployment of these serverless Azure functions base RESTful web APIs. The only advantage here is the focus on building business logic rather than worrying about the backend infrastructure for deployment. Currently, Azure cloud or any on premise server can run these serverless Azure functions REST web API. Azure functions although provides more than just developing RESTful web APIs, but for now my focus is on building Authorized RESTful web APIs with azure functions and later integrated that API with Android MAUI.NET8 platform.
 
Today, I shall be demonstrating integration of Authorized Azure Functions HTTP RESTful web APIs with Android MAUI.NET8 platform using SQLite database and Android MAUI Secure Storage.


Prerequisites:

Before proceeding any further in this article, following are some of the many prerequisites for this article:
  1. Knowledge of Android MAUI.NET8 Platform
  2. Knowledge of RESTful Web APIs.
  3. Knowledge of C# Programming.
The running working source code solution for this article is being developed in Microsoft Visual Studio 2022 Professional. For the source code click on the download button below.

Download Now!


Authorization Scheme

There are many ways in which authorization of azure functions can be done such as Azure Storage Cloud and Azure Key Vault, but, these mechanisms require Azure portal subscriptions. However, there in another way which is based on a secret API key and which is absolutely free of cost. The idea here is to randomly generate an API key from android app side each time the application is launched. Then first delete any already existing API key and then save the newly generated API key in a MAUI secure storage. Next, send this newly generated key to the azure function HTTP POST API and save this API key in the SQLite database at azure function server side. Now, that the Azure functions authorization scheme has been established, this API key can be used as a secret API key to gain access to authorize Azure HTTP functions.
 
Let's begin now.
 

Develop Azure Function Server

1) In the first step, create a new "Azure Functions" project and name it "AzServerlessApiFunc". Make sure to select below listed settings while creating the azure function project. Select .NET8 isolated as functions worker, HTTP Trigger as function and function as authorization level. For function level authorization, azure function requires API key as authorization, while anonymous level authorization allows anyone to access the azure function HTTP API. I am creating both authorization level azure functions, which I will show later on. For now, choose below settings.

 



 2) I have changed my azure function default auto scaffold signature to something like shown below i.e.

...

        [Function("GetCountryListApi")]
        public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = "getCountryList")] HttpRequestData request)
        {
            // Initialization
            HttpResponseData response = null;

            // Do Something

        }            

...


The important part here is  "HttpRequestData" class, which is essential part of azure function to receive more complex request data. I have add the route to my API and I have also make this particular function to be HTTP GET. This is the authorized Azure function which cannot be accessed without API key. This particular function returns the county list data.


3) Next, Install following list of packages using nuget package manager i.e.

  1. Newtonsoft.Json
  2. CSVLibraryAK.Core
  3. sqlite-net-pcl




4) Now, before creating another Azure function HTTP trigger. Create the SQLite database. To do so, create a new "AzServerlessApiFuncDatabase" class, which will contain all the necessary functions to create target database along with tables and CRUD operation methods. To give you a quick idea, the class will look something like below i.e.

...

    /// <summary>
    /// Azure Serverless API Function Database Class
    /// </summary>
    internal class AzServerlessApiFuncDatabase
    {
        #region Private Properties

        /// <summary>
        ///  Gets or sets Database property.
        /// </summary>
        private readonly SQLiteAsyncConnection _database;

        #endregion

        #region Default Constructor method

        /// <summary>
        /// Initializes a new instance of the <see cref="AzServerlessApiFuncDatabase"/> class.
        /// </summary>
        /// <param name="dbPath">Database Path parameter</param>
        public AzServerlessApiFuncDatabase(string dbPath)
        {
            ...

                // Settings.
                this._database = new SQLiteAsyncConnection(dbPath);

                //create Database Tables.

            ... 
        }

        #endregion

        #region Insert Key Value Pair method

        /// <summary>
        /// Insert Key Value Pair method
        /// </summary>
        /// <param name="keyValPairObj">Key valur pair object parameter</param>
        /// <returns> Return 0 if no data is inserted, otherwise greater than 0 value is returned </returns>
        public int InsertKeyValuePairAsync(KeyValuePairTable keyValPairObj)
        {
            // Initialization.
            int rowCount = 0;

            ...

            // Insert operation.

            ...

            // Info.
            return rowCount;
        }

        #endregion

        #region Read Key Value Pair method

        /// <summary>
        /// Read Key Value Pair method
        /// </summary>
        /// <returns> Return 0 if no data is inserted, otherwise greater than 0 value is returned </returns>
        public async Task<List<KeyValuePairTable>> ReadKeyValuePairAsync()
        {
            // Initialization.
            List<KeyValuePairTable> lst = new List<KeyValuePairTable>();

            ...

            // Read operation.

            ...

            // Info.
            return lst;
        }

        #endregion
    }

...


5)
Next, within the azure function class, create a private read only property "databaseManager" to access all the database operations. You also need to initialize the databaseManager property within the azure function class default constructor with the database access class that I have created previously as show below i.e.

...

        /// <summary>
        /// Gets or sets Database Manager property.
        /// </summary>
        private readonly AzServerlessApiFuncDatabase databaseManager;

        /// <summary>
        /// Initializes a new instance of the <see cref="AzFuncApi"/> class.
        /// </summary>
        /// <param name="logger">Logger parameter</param>
        public AzFuncApi(ILogger<AzFuncApi> logger)
        {
            ...

                // Varification.
                if (this.databaseManager == null)
                {
                    // Get path location for database file.

                    // Setting.
                    this.databaseManager = new AzServerlessApiFuncDatabase(databasePath);
                }

            ...
        }

        #endregion

...


6)
It's time to create another azure function but with anonymous authorization level. This particular azure function will save the API key into data as per the authorization scheme that I have already explained. This azure function will be a HTTP POST type method, which will take JSON input of API key name and API key value. Normally, when such HTTP POST API is created the signature of the method have an HttpReqesMessage type input and JToken form body type input. Since, in azure function HttpRequestData type input is supported, so, the method signature will look something like as shown below i.e.

...

using FromBodyAttribute = Microsoft.Azure.Functions.Worker.Http.FromBodyAttribute;

...

        [Function("SaveKeyValuePairApi")]
        public async Task<HttpResponseData> SaveKeyValuePair([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "saveKeyValuePair")] HttpRequestData request, [FromBody] JToken postData)
        {
            // Initialization
            HttpResponseData response = null;

            // Do Something.

        }
...


In the above code, you need to include the using FormBodyAttribute library if you are going to use [FormBody] attribute within the method signature. When you you try to call this API using RESTED client. You will get error instead as shown below. The reason is that azure function cannot map JSON type input to JToken type like normal ASP.NET MVC or Core web API does.




7) To fix the above issue, the normal thinking is to post a JSON serialized string from client side and then deserialize the JSON string at API side. This means change the [Form body] parameter from JToken type to string instead as shown below. When the API is now called from the RESTED client, the response is successful, but, when similar API is called from android MAUI app using HttpClient class, an error occurs because azure function [FormBody] remains empty for some reason causing server side failure. This issue is happening in .NET8.

...

using FromBodyAttribute = Microsoft.Azure.Functions.Worker.Http.FromBodyAttribute;

...

        [Function("SaveKeyValuePairApi")]
        public async Task<HttpResponseData> SaveKeyValuePair([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "saveKeyValuePair")] HttpRequestData request, [FromBody] string postData)
        {
            // Initialization
            HttpResponseData response = null;

            // Do Something.

        }
...






 

8) Now, to fix this issue especially when called from the android MAUI app. For .NET 8 isolated, the azure function signature is written as shown below, the form body will be captured by HttpRequestData class. Also, no need to include form body using library reference.

...

        [Function("SaveKeyValuePairApi")]
        public async Task<HttpResponseData> SaveKeyValuePair([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "saveKeyValuePair")] HttpRequestData request)
        {
            // Initialization
            HttpResponseData response = null;

            // Do Something.

        }
...


The input request data from the above signature can be extracted in three ways as shown below i.e.

...

string postData = new StreamReader(request.Body).ReadToEnd();

...


The above will capture the input request data as string. If you have sent JSON format then you can deserialize the above string into your target object.

...

KeyValuePairTable requestObj = await request.ReadFromJsonAsync<KeyValuePairTable>();

...


The above line of code allows to directly extract the input request JSON into the target object.

...

var query = System.Web.HttpUtility.ParseQueryString(req.Url.Query);

...


If you have passed the input data as URL query input then you can use the above line of code to extract the input request query data.

Develop Android MAUI App

Now that azure function REST web APIs are developed and tested successfully, It is time to create a simple Android MAUI app that loads country list data from azure function REST web API.


1)   Create a new ".NET MAUI Multi-Project App" project and name it "AndroidMauiAzApi". Make sure to select .NET 8 as your framework and only select Android as the platform as shown below i.e. 

 


2)
Next, Install following list of packages using nuget package manager i.e.

  1. Newtonsoft.Json
  2. Microsoft.AspNet.WebApi.Client



3) Remember, MAUI secure storage on android is temporary, this means that it should not be auto-backup, but I also don't want to turn off the auto-backup. Luckily, MAUI android platform has a solution to only tun the partial auto-backup off for secure storage only. To do this expand the prject to "AndroidMauiAzApi.Droid->Resources" and then create "xml" folder.


4) Next, create "auto_backup_rules.xml" file under "AndroidMauiAzApi.Droid->Resources->xml" folder. Open the file and copy below lines of code within the file i.e.

<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
  <include domain="sharedpref" path="."/>
  <exclude domain="sharedpref" path="${applicationId}.microsoft.maui.essentials.preferences.xml"/>
</full-backup-content>


5)
Now, open the "AndroidMauiAzApi.Droid->AndroidManifest.xml" file in the XML editor and add below line of code at the end of application tag as shown below i.e.

...

<application ...
    android:fullBackupContent="@xml/auto_backup_rules">
</application>

...


6)
Since, the Azure function RESTful web API is currently running on local server, therefore, some additional configurations at MAUI android end is needed to successfully test the azure function API integration with MAUI android app. To do so, open "AndroidMauiAzApi.Droid->MainApplication.cs" file and replace [Application] attribute as shown below i.e.

#if DEBUG
    [Application(UsesCleartextTraffic = true)]
#else
    [Application]
#endif


7)
Then, create "network_security_config.xml" file under "AndroidMauiAzApi.Droid->Resources->xml" folder. Open the file and copy below lines of code within the file. You need to replace the IP address 10.0.2.2 within this file with your IP address i.e.

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">10.0.2.2</domain>
  </domain-config>
</network-security-config>


8) Now, open the "AndroidMauiAzApi.Droid->AndroidManifest.xml" file in the XML editor and add below line of code at the start of application tag as shown below i.e.

...

    <application android:networkSecurityConfig="@xml/network_security_config" ...>
        ...
    </application>

...


9)
Next, create the HTTP GET and POST APIs using HttpClient class to access the azure function RESTful web API within "AndroidMauiAzApi" project.

10) In the "App.xaml.cs" class file default constructor build the logic to save the API key inside the secure storage and call the Azure function HTTP POST method to save the generated API key at the server side as well. This is necessary, as this logic will execute only at the launch of the application.


11)
Build the necessary List View and a button to call the authorize azure function HTTP GET API to get the country list data within the "MainPage.xaml" & "MainPage.xaml.cs" files.


12) Execute the azure function project first and keep it running. Then execute the android MAUI app project and click the "Load" button on the android app to get data from azure function RESTful web API as shown below i.e.




Conclusion

In this article, you will learn to integrate Authorized Azure Functions HTTP RESTful web APIs with Android MAUI.NET8 platform using SQLite database and Android MAUI Secure Storage. You will learn about free of cost authorization scheme for securing Azure Function REST web API using secret API key. You will also learn about creating SQLite database and secure storage as a part of authorization scheme. You will learn to enable localhost API testing from android app using HttpClient class. You will also enable partial auto-back on android MAUI app to ignore the secure storage auto-backup. Finally, develop and execute both azure function server and Android MAUI app.

No comments