.Net MAUI, Local Web Api Access From Mob...

  • Home
  • / .Net MAUI, Local Web Api Access From Mob...

image

05 Feb 2024

09

35

Introduction

This documentation shows you how you can configure Local Api Access From Android Phone.

In the context of MAUI (Multi-platform App UI) development, accessing a local WebAPI from mobile devices introduces specific considerations. MAUI facilitates cross-platform app development for Android, iOS, and Windows with a single codebase, using .NET MAUI and Xamarin.Forms technologies. When dealing with local WebAPIs, developers may encounter challenges related to device emulators, network configurations, and security protocols.

Imagine code like this git git As you can see the api call succeded for windows app but not for android app.

So what can we do about it?

Lets modify the code to make it work in android git

You need to add some code like this to make it work

    public class HttpsClientHandlerService : IHttpsClientHandlerService
    {
        public HttpMessageHandler GetPlatformMessageHandler()
        {
 #if ANDROID
            var handler = new Xamarin.Android.Net.AndroidMessageHandler();
        handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
        {
            if (cert != null && cert.Issuer.Equals("CN=localhost"))
                return true;
            return errors == System.Net.Security.SslPolicyErrors.None;
        };
        return handler;
#elif IOS
            var handler = new NSUrlSessionHandler
            {
                TrustOverrideForUrl = IsHttpsLocalhost
            };
            return handler;
#else
            //throw new PlatformNotSupportedException("Only Android and iOS supported.");
            return new HttpClientHandler();
#endif
        }

#if IOS
        public bool IsHttpsLocalhost(NSUrlSessionHandler sender, string url, Security.SecTrust trust)
        {
            if (url.StartsWith("https://localhost"))
                return true;
            return false;
        }
#endif
    }

Then again windows app will not work with url 10.0.2.2

So what is the ultimate solution?

The ultimate solution is to write code something like this

public interface IHttpsClientHandlerService
{
    HttpMessageHandler GetPlatformMessageHandler();
}

public class HttpClientOptions
{
    public string? BaseAddress { get; set; }
    public string? LocalAddress { get; set; }
    public string? RemoteAddress { get; set; }
    // public DeviceType DeviceType { get; set; }
    public TimeSpan Timeout { get; set; }
    public IDictionary<string, string> DefaultRequestHeaders { get; set; }
    public string? BearerToken { get; set; }
    public int PortNumber { get; set; } // New property for port number

    public HttpClientOptions()
    {
        DefaultRequestHeaders = new Dictionary<string, string>();
        PortNumber = 7101;
        RemoteAddress = "https://evanapi.azurewebsites.net";
    }
}

public class HttpClientOptionstightCoupled
{
    public string? BaseAddress { get; set; }
    public string? LocalAddress { get; set; }
    public string? RemoteAddress { get; set; }
    // public DeviceType DeviceType { get; set; }
    public TimeSpan Timeout { get; set; } = new TimeSpan(10);
    public IDictionary<string, string> DefaultRequestHeaders { get; set; }
    public string? BearerToken { get; set; }
    public int PortNumber { get; set; } 
    public IHttpsClientHandlerService? httpsClientHandlerService { get; set; } 

    public HttpClientOptionstightCoupled()
    {
        DefaultRequestHeaders = new Dictionary<string, string>();
        PortNumber = 7101;
        RemoteAddress = "https://evanapi.azurewebsites.net";
    }
}
public static class EvanHttpClientExtensions
{

    public static void AddEvanHttpClient(this IServiceCollection services, Action<HttpClientOptions, IHttpsClientHandlerService> configureOptions)
    {
        services.AddScoped<HttpClient>(sp =>
        {
            HttpClient? httpClient = null;
            var options = new HttpClientOptions();
            
          

            IHttpsClientHandlerService httpsClientHandlerService = sp.GetRequiredService<IHttpsClientHandlerService>();
            configureOptions(options, httpsClientHandlerService);

            HttpMessageHandler handler = httpsClientHandlerService.GetPlatformMessageHandler();
            httpClient = new HttpClient(handler);
           

            string? baseAddress = options.BaseAddress;

            DeviceType deviceType = DeviceInfo.DeviceType;
            if (!string.IsNullOrEmpty(baseAddress))
            {
                if (deviceType == DeviceType.Virtual)
                {
                    baseAddress = $"https://10.0.2.2:{options.PortNumber}"; // Android Virtual Device
                    httpClient.BaseAddress = new Uri(baseAddress);
                }
                else
                {
                    httpClient.BaseAddress = new Uri(baseAddress);
                }
            }
            else
            {
                try
                {
                    if (deviceType == DeviceType.Virtual)
                    {
                        baseAddress = $"https://10.0.2.2:{options.PortNumber}";
                    }
                    else if (deviceType == DeviceType.Physical)
                    {
                        if (DeviceInfo.Platform == DevicePlatform.Android)
                        {
                            baseAddress = options.RemoteAddress;
                        }
                        else if (DeviceInfo.Platform == DevicePlatform.iOS)
                        {
                            baseAddress = "YOUR_IOS_BASE_URL"; // Replace with iOS base URL
                        }
                        else if (DeviceInfo.Platform == DevicePlatform.WinUI)
                        {
                            baseAddress = $"https://localhost:{options.PortNumber}";
                        }

                        else
                        {
                            baseAddress = $"https://localhost:{options.PortNumber}";
                        }
                    }
                    else
                    {
                        baseAddress = $"https://localhost:{options.PortNumber}";
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                    baseAddress = "DEFAULT_BASE_URL";
                }
                httpClient.BaseAddress = new Uri(baseAddress);
            }

            httpClient.Timeout = options.Timeout;

            if (options.DefaultRequestHeaders?.Count > 0)
            {
                foreach (var header in options.DefaultRequestHeaders)
                {
                    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
            }

            if (!string.IsNullOrEmpty(options.BearerToken))
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", options.BearerToken);
            }

            return httpClient;
        });
    }
    public static void AddEvanHttpClientTightCoupled(this IServiceCollection services, Action<HttpClientOptionstightCoupled> configureOptions)
    {
        services.AddScoped<HttpClient>(sp =>
        {
            HttpClient? httpClient = null;
            var options = new HttpClientOptionstightCoupled();
            configureOptions(options);
            HttpMessageHandler handler = options.httpsClientHandlerService!.GetPlatformMessageHandler();
            httpClient = new HttpClient(handler);


            string? baseAddress = options.BaseAddress;

            DeviceType deviceType = DeviceInfo.DeviceType;
            if (!string.IsNullOrEmpty(baseAddress))
            {
                if (deviceType == DeviceType.Virtual)
                {
                    baseAddress = $"https://10.0.2.2:{options.PortNumber}"; // Android Virtual Device
                    httpClient.BaseAddress = new Uri(baseAddress);
                }
                else
                {
                    httpClient.BaseAddress = new Uri(baseAddress);
                }
            }
            else
            {
                try
                {
                    if (deviceType == DeviceType.Virtual)
                    {
                        baseAddress = $"https://10.0.2.2:{options.PortNumber}";
                    }
                    else if (deviceType == DeviceType.Physical)
                    {
                        if (DeviceInfo.Platform == DevicePlatform.Android)
                        {
                            baseAddress = options.RemoteAddress;
                        }
                        else if (DeviceInfo.Platform == DevicePlatform.iOS)
                        {
                            baseAddress = "YOUR_IOS_BASE_URL"; // Replace with iOS base URL
                        }
                        else if (DeviceInfo.Platform == DevicePlatform.WinUI)
                        {
                            baseAddress = $"https://localhost:{options.PortNumber}";
                        }

                        else
                        {
                            baseAddress = $"https://localhost:{options.PortNumber}";
                        }
                    }
                    else
                    {
                        baseAddress = $"https://localhost:{options.PortNumber}";
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                    baseAddress = "DEFAULT_BASE_URL";
                }
                httpClient.BaseAddress = new Uri(baseAddress);
            }

            //httpClient.Timeout = options.Timeout;

            if (options.DefaultRequestHeaders?.Count > 0)
            {
                foreach (var header in options.DefaultRequestHeaders)
                {
                    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
            }

            if (!string.IsNullOrEmpty(options.BearerToken))
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", options.BearerToken);
            }

            return httpClient;
        });
    }

}

In this case access to webapi succeded for both Android and Windows app.

I will explain this code in my future posts.

Join our newsletter!

Enter your email to receive our latest newsletter.

Don't worry, we don't spam

image

Related Articles

image
14 Feb 2024

Deploying a FREE Nodejs Serverless API in Vercel with Zenstack, Prisma and Neon's Free PostgreSQL

Explore the process of deploying a serverless API with Vercel, leveraging Zenstack for Prisma integration, TypeScript for enhanced development, and Neon's complimentary PostgreSQL database for your project. -by Evan Dangol

image
07 Feb 2024

Harnessing Machine Learning to Detect Toxic Comments - Using Calibrated Binary Classification Metrics Module

Unveiling Machine Learning's Power- Detecting Toxic Comments with C# -by Evan Dangol

image
06 Feb 2024

Will gRPC ultimately replace REST Api in future? A simple gRPC using nodejs with Nextjs

It's unlikely that gRPC will entirely replace REST (Representational State Transfer) API in the near future, as both technologies have their own strengths and are suitable for different use cases.gRPC (Google Remote Procedure Call) is a high-performance...