Xamarin and the HttpClient For iOS, Android and Windows

Xamarin and the HttpClient For iOS, Android and Windows

In an earlier post that talked about using dependency injection and registering interfaces for working with Refit across both Prism and MvvmCross I had code that registered an instance of the CustomHttpMessageHandler class which internally used a HttpClientHandler for its InnerHandler. For developers who have spent a bit of time optimising their iOS, Android or Windows application, you’ll have noted that using the HttpClientHandler is generally not deemed to be best practice.  As I’m a big fan of trying to demonstrate best practices, I figured I’d expand on this a little into a post talking about the HttpClient and some of the options you have.

Firstly, a couple of bits of side reading:

– Docs on the HttpClient stack

– Mono blog post talking about the HttpWebRequest / HttpClient

– Jon’s post on Http Performance

What you should gather from these articles is that Microsoft is doing their best to set you up for success but not wanting to take any documentation for granted, let’s see what happens when we create a brand new Xamarin.Forms project and spin up an instance of the HttpClient. When creating the project I just picked the Blank Xamarin.Forms template and made sure that all three platforms were included. The code for creating the HttpClient just uses the zero-parameter constructor:

var client = new HttpClient();

Let’s run each platform and see what the HttpClient gives us (and at this point I haven’t updated any NuGet packages, framework versions or anything. This is just what VS2019 gives me when I create a new XF project).

UWP

image

Here we get the managed HttpClientHandler, rather than the newer (and arguably better) WinHttpHandler. Actually I didn’t find a definitive guide on which is better for UWP, although this stackoverflow post does seem to imply the WinHttpHandler would be the preferred choice, particularly if you want to leverage Http/2.

Android

image

Android is using the AndroidClientHandler which is what should give us the most up to date http experience.

iOS

image

iOS is using the NSUrlSessionHandler which is what should give us the most up to date http experience.

This all seems good (albeit that you might want to use the WinHttpHandler on UWP) so for a lot of developers they might never run into any issues. If you did want to adjust which handler is used on iOS and Android (again assuming you’re just using the HttpClient with the default constructor) you can do so via the properties dialog for the corresponding platform:

image

However, where things come unstuck is if you want to customise some of the http behaviour. In my previous post I demonstrated setting the compression flag but it could have equally been adding an additional header or changing the credentials that are sent as part of each request. In this case, it’s easy enough to use the overload of the HttpClient constructor that takes a HttpMessageHandler and use the managed HttpClientHandler implementation (as I demonstrated). As you’d have seen from the linked articles above, this isn’t ideal as the managed implementation doesn’t leverage the platform specific optimisations.

The better approach is for my application to register the platform specific handler, which in MvvmCross can be done via the Setup class (which is created by default when using MvxScaffolding):

UWP

public class Setup : MvxFormsWindowsSetup<Core.App, UI.App>
{
     protected override void InitializeIoC()
     {
         base.InitializeIoC();
        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
         {
             return new WinHttpHandler()
             {
                AutomaticDecompression = options.Compression
             };

         });
     }
}

Android

public class Setup : MvxFormsAndroidSetup<Core.App, UI.App>
{
     protected override void InitializeIoC()
     {
         base.InitializeIoC();


        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
         {
            return new AndroidClientHandler
             {
                 AutomaticDecompression = options.Compression
             };

         });
     }
}

iOS

public class Setup : MvxFormsIosSetup<Core.App, UI.App>
{
     protected override void InitializeIoC()
     {
         base.InitializeIoC();


        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
         {
             var nsoptions = NSUrlSessionConfiguration.DefaultSessionConfiguration;
             if (options.Compression == System.Net.DecompressionMethods.None)
             {
                 nsoptions.HttpAdditionalHeaders = new NSDictionary(“Accept-Encoding”, “identity”, new object[] { });
             }
             var handler = new NSUrlSessionHandler(nsoptions);
             return handler;

         });
     }
}

Note: for iOS the NSUrlSessionHandler enabled compression by default, so the code here illustrates how you could disable compression if you wanted by sending the identity Accept-Encoding header.

In this post I’ve shown you how you can register each of the native platform handlers to optimise the requests made when using the HttpClient. This post should be read in conjunction with my earlier post that registered the other classes necessary to create the HttpClient based on the registered handler. The only other change is that the HttpService constructor should accept an HttpMessageHandler instead of an ICustomHttpMessageHandler.

public class HttpService : IHttpService
{
     public HttpService(HttpMessageHandler httpMessageHandler, IServiceOptions options)
     {
         HttpClient = new HttpClient(httpMessageHandler as HttpMessageHandler)
         {
             BaseAddress = new Uri(options.BaseUrl)
         };
     }


    public HttpClient HttpClient { get; }
}

Update: It’s worth noting that the WinHttpHandler used in the UWP example isn’t part of the core framework. Instead it is accessible via the System.Net.Http.WinHttpHandler NuGet package. Visual Studio provides a handy way to find and install this package – selecting the WinHttpHandler reference (where there is a build error) and looking at the intellisense options, there is an option to Install the System.Net.Http.WinHttpHandler package.

image

Lazy Dependencies and Interfacing Refit with MvvmCross and Prism

Lazy Dependencies and Interfacing Refit with MvvmCross and Prism

Refit is one of those libraries that makes your life as a developer having to write code to work with services that much easier. By way of an example let’s look at the GET List Users method from the sample REST service available at https://reqres.in/

image

Running the response json through JsonToCSharp we get a class model similar to:

public class User
{
     public int id { get; set; }


    public string first_name { get; set; }


    public string last_name { get; set; }


    public string avatar { get; set; }
}


public class UserList
{
     public int page { get; set; }


    public int per_page { get; set; }


    public int total { get; set; }


    public int total_pages { get; set; }


    public List<User> data { get; set; }
}

Next we define the interface for our service (Note that the Get attribute defines the path, including the page parameter that’s passed into the RetrieveUsers method):

public interface IUserService
{
     [Get(“/api/users?page={page}”)]
     Task<UserList> RetrieveUsers(int page);
}

Of course, we need to add a reference to the Refit NuGet package to our application. Lastly we of course need to retrieve an instance of the UserService, which is where the magic comes in – behind the scene, Refit generates the appropriate implementation for the IUserService so that all you need to do is retrieve it using code similar to:

var userService = RestService.For<IUserService>(“https://reqres.in/”);

This is all well and good but when it comes to writing applications using Prism or MvvmCross, what we really want to be able to do is have the IUserService injected into the constructor of our view model.

Injecting Refit with MvvmCross

We’ll start with MvvmCross (I’ve create a brand new project using MvxScaffold to get me started) and I’ve modified the HomeViewModel to add IUserService as a parameter to the constructor. The service is then used in the ViewAppeared method to retrieve the first page of users.

public class HomeViewModel : BaseViewModel
{
     private IUserService UserService { get; }
     public HomeViewModel(IUserService userService)
     {
         UserService = userService;
     }


    public override async void ViewAppeared()
     {
         base.ViewAppeared();


        var users = await UserService.RetrieveUsers(1);
         Debug.WriteLine(users.data.Count);

     }
}

Now the trick is that we need to register the instance of the IUserService with MvvmCross which we can do at the end of the Initialize method of App.cs in the Core project. We don’t want all of the services to be created at start-up, so instead we register the type using the LazyConstructAndRegisterSingleton extension method: For example:

public override void Initialize()
{
     …
     Mvx.IoCProvider.LazyConstructAndRegisterSingleton<IUserService>
         (() => RestService.For<IUserService>(“https://reqres.in/”));
}

There’s a couple of issues here:

– String literal for the host url

– No ability to override the HttpClient used by the IUserService implementation

Let’s see how we can resolve this by registering some other instances that we can use as part of creating the IUserService. One of the other options for the For method is that we can supply a HttpClient that already has a BaseAddress set. We can also set a HttpMessageHandler on the HttpClient instance that will allow us to customise the behaviour of the HttpClient. Unfortunately the only interface that the HttpClient implements is IDisposable. To get around this we wrap the HttpClient instance in a service which returns the instance as a property:

public interface IHttpService
{
     HttpClient HttpClient { get; }
}


public class HttpService : IHttpService
{
     public HttpService(ICustomHttpMessageHandler customHttpMessageHandler, IServiceOptions options)
     {
         HttpClient = new HttpClient(customHttpMessageHandler as HttpMessageHandler)
         {
             BaseAddress = new Uri(options.BaseUrl)
         };
     }
     public HttpClient HttpClient { get; }
}

Note that in this example the HttpService implementation relies on an ICustomHttpMessageHandler and IServiceOptions. These are here to illustrate the chaining of dependencies that can all be lazy loaded.

public interface ICustomHttpMessageHandler
{
}
public class CustomHttpMessageHandler : DelegatingHandler, ICustomHttpMessageHandler
{
     public CustomHttpMessageHandler(IServiceOptions options)
     {
         InnerHandler = new HttpClientHandler()
         {
             AutomaticDecompression = options.Compression
         };
     }
}
public interface IServiceOptions
{
     string BaseUrl { get; }
     DecompressionMethods Compression { get; }
}
public class ServiceOptions : IServiceOptions
{
     public string BaseUrl { get; set; }
     public DecompressionMethods Compression { get; set; }
}

The final registration code in the Initialize method is:

public override void Initialize()
{
     …
     Mvx.IoCProvider.LazyConstructAndRegisterSingleton<IServiceOptions>(() => new ServiceOptions()
     {
         BaseUrl = “https://reqres.in”,
         Compression = DecompressionMethods.Deflate | DecompressionMethods.GZip
     });
     Mvx.IoCProvider.LazyConstructAndRegisterSingleton<ICustomHttpMessageHandler, CustomHttpMessageHandler>();
     Mvx.IoCProvider.LazyConstructAndRegisterSingleton<IHttpService, HttpService>();
     Mvx.IoCProvider.LazyConstructAndRegisterSingleton<IUserService, IHttpService>
         (service => RestService.For<IUserService>(service.HttpClient));
}

Injecting Refit with Prism

I’m not going to cover over generating the classes and IUserService interface. Instead we’re going to look at how we can register and then make use of the IUserService within Prism. One of the limitations of Prism is that there is no way to register a singleton for lazy creation using a function callback. This means we’d need to register an actual implementation of the IUserService which would mean creating the service instance on app startup instead of when the service is first used. Luckily there is a work around that makes use of the Lazy<T> class. Again, the Lazy<T> doesn’t implement an interface, so we’ll inherit from Lazy<T> and implement a new interface ILazyDependency.

public interface ILazyDependency<T>
{
     T Value { get; }
}
public class LazyDependency<T> : Lazy<T>, ILazyDependency<T>
{
     public LazyDependency(Func<T> valueFactory) : base(valueFactory)
     {
     }
}

And now here’s the registration code (added to the RegisterTypes method in App.xaml.cs):

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
     …
     containerRegistry.RegisterInstance<IServiceOptions>(new ServiceOptions()
     {
         BaseUrl = “https://reqres.in”,
         Compression = DecompressionMethods.Deflate | DecompressionMethods.GZip
     });
     containerRegistry.RegisterSingleton<ICustomHttpMessageHandler, CustomHttpMessageHandler>();
     containerRegistry.RegisterSingleton<IHttpService, HttpService>();
     containerRegistry.RegisterInstance<ILazyDependency<IUserService>>(
         new LazyDependency<IUserService>(() =>
         RestService.For<IUserService>(
             PrismApplicationBase.Current.Container.Resolve<IHttpService>().HttpClient)
         ));
}

This code looks very similar to the registration code when using MvvmCross. However, the difference is that instead of registering IUserService, it registers ILazyDependency<IUserService>. This is important to note because we need to remember to request the correct interface instance in our view model:

public class MainPageViewModel : ViewModelBase
{
     private IUserService UserService { get; }
     public MainPageViewModel(INavigationService navigationService, ILazyDependency<IUserService> userService)
         : base(navigationService)
     {
         UserService = userService.Value;
         Title = “Main Page”;
     }
     public override async void OnNavigatedTo(INavigationParameters parameters)
     {
         base.OnNavigatedTo(parameters);


        var users = await UserService.RetrieveUsers(0);
         Debug.WriteLine(users.data.Count);
     }
}

And there you have it, we’ve abstracted the Refit implementation away from our view models, making them ready for testing.

#The following code was added to the MvvmCross project to simplify the registration of the IUserService:

public static class MvxIoCContainerExtensions
{
     private static Func<TInterface> CreateResolver<TInterface, TParameter1>(
         this IMvxIoCProvider ioc,
             Func<TParameter1, TInterface> typedConstructor)
             where TInterface : class
             where TParameter1 : class
     {
         return () =>
         {
             ioc.TryResolve(typeof(TParameter1), out var parameter1);
             return typedConstructor((TParameter1)parameter1);
         };
     }


    public static void LazyConstructAndRegisterSingleton<TInterface, TParameter1>(this IMvxIoCProvider ioc, Func<TParameter1, TInterface> constructor)
         where TInterface : class
         where TParameter1 : class
     {
         var resolver = ioc.CreateResolver(constructor);
         ioc.RegisterSingleton(resolver);
     }
}

Note: This code has already been merged into MvvmCross but at time of writing isn’t in the stable release.

Resolving Dependencies In Platform Pages, Renderers, Effects and Elements with Xamarin.Forms and Prism

Resolving Dependencies In Platform Pages, Renderers, Effects and Elements with Xamarin.Forms and Prism

We’ve been using Prism for a number of our Xamarin.Forms projects and for the most part we rely on the services being injected into our view models but a scenario came up recently where we wanted to access one of our services from within the platform implementation of a renderer. We were using DryIoC and needed to come up with a mechanism to resolve dependencies that had been registered with DryIoC via Prism. I recalled seeing in Brian’s What’s New in Prism 7.1 post that support had been added for the Xamarin.Forms Dependency Resolver and was wondering whether we could use that to allow us to resolve dependencies by calling Resolve on the static DependencyService that Xamarin.Forms exposes. In this post I’m going to walk through creating a simple Prism application, register a service and then retrieve it from the code behind of a UWP page (but the same process applies for any renderer, effect, page or element).

To get started with a new Prism application I’m going to make use of the Prism Template Pack that installs as a Visual Studio Extension and includes a variety of project and item templates. In Visual Studio 2019 when you launch the application you can select Create a New Project and be given the option to search for project templates.

image 

Once you’ve selected the Prism Bank App (Xamarin.Forms) you’ll then be prompted to specify the name and location of the project

image

The final step is a Prism specific dialog that allows you to specify which platforms and what IoC container you want to use

image

In this case we’re going with DryIoC but I think the technique will work equally well if you select AutoFac or Unity. After hitting Create Project our solution is setup with four projects: one for each target platform and a project that contains both our view and view models. 

image

My preference is to separate views and viewmodels further but for the timebeing we’ll leave the project structure as it is. The next step is to create and register the service that we want to retrieve from our platform specific code.

public interface IFancyService
{
     string WelcomeText { get; }
}


public class MyFancyService : IFancyService
{
     public string WelcomeText => “Hello Dependency World!”;
}

The MyFancyService needs to be registered with the DI container, which we can do by adding a line to the RegisterTypes method in the App.xaml.cs

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
     containerRegistry.RegisterForNavigation<NavigationPage>();
     containerRegistry.RegisterForNavigation<MainPage, MainPageViewModel>();


    containerRegistry.Register<IFancyService, MyFancyService>();
}

Let’s switch across to the code behind of the MainPage in the UWP application – note that this page is different from the MainPage that’s in the Xamarin.Forms project which is the page that’s displayed on all platforms. The MainPage in the UWP project is used to host the Xamarin.Forms application when it’s run on Windows. I’m going to add the OnNavigatedTo override method and in it I’m going to attempt to resolve the IFancyService interface using the Xamarin.Forms DependencyService.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
     base.OnNavigatedTo(e);


    var fancy = DependencyService.Resolve<IFancyService>();
}

Running this code we’ll see that the variable fancy is null, meaning that the Resolve method wasn’t able to find any registered implementation of the IFancyService.

image

To fix this, we need to tell Prism to register as a Dependency Resolver, which will mean that the Xamarin.Forms DepedencyService will use the same DI container when resolving instances. This is done by using the overloaded constructor of the PrismApplication class. In the App.xaml.cs of our application, change the call to base to include a second parameter which is set to true.

public App(IPlatformInitializer initializer) : base(initializer, setFormsDependencyResolver: true)
{
}

Running the application now and the fancy variable is set to an instance of the MyFancyService.

image

And there you have it – an easy way to use the Xamarin.Forms DependencyService in conjunction with Prism and DryIoC.

Getting Started with Xamarin.Forms, Refactoring MvvmCross and Services

Getting Started with Xamarin.Forms, Refactoring MvvmCross and Services

Previous posts in this sequence:
Getting Started with Xamarin.Forms and Multi-Targeting in Visual Studio
Getting Started with Xamarin.Forms and SDK Versions
Getting Started with Xamarin.Forms with MvvmCross
Getting Started with Xamarin.Forms and Authenticating with ADAL

In this post I’m going to do a bit of a refactor based on the work completed in the previous post where we added code directly into the MainViewModel to use the Azure Active Directory Authentication Library. This would be fine if the MainViewModel was the only view model in the application that needed access to the Authenticate method. As I will probably want to make use of it elsewhere, I’ve decided to refactor that code into a class called CredentialService.

When I wired up MvvmCross a couple of posts ago, I did so without going into much detail on how the relationship between view models and their corresponding page is setup. I’m not going to delve into the inner workings of MvvmCross but suffice to say that there is some reflection magic that goes on based on the names of the classes. A view model with the name MainViewModel will be paired with a page called MainPage.

In addition to the magic that glues the view model and pages together (and thus the navigation model) MvvmCross also has a quite powerful dependency injection framework. The CredentialService that I’ll be creating will be registered with the DI framework as a singleton that can be easily accessed.

Let’s start by creating the CredentialService and it’s corresponding interface ICredentialService in a folder called Services in the Core library.

public partial class CredentialService:ICredentialService
{
     private const string AuthEndpoint = “
https://login.microsoftonline.com/{0}/oauth2/token”;


    private const string ResourceId = “https://graph.windows.net/”;
     private const string TenantId = “[your tenantId]”;
     private const string ClientId = “[your clientId]”;
     private const string RedirectURI = “[your redirectURI]”;


    public string AccessToken { get; set; }


    public async Task<string> Authenticate()
     {
         string authority = string.Format(CultureInfo.InvariantCulture, AuthEndpoint, TenantId);
         var authContext = new AuthenticationContext(authority);


        var result = await authContext.AcquireTokenAsync(ResourceId, ClientId, new Uri(RedirectURI), this.PlatformParameters);
         AccessToken = result.AccessToken;
         return AccessToken;
     }
}

public interface ICredentialService
{
     Task<string> Authenticate();
}

The platform specific code will need to be extracted out of the MainViewModel.Platform.cs into the corresponding CredentialService.Platform.cs. For example the UWP class would be:

public partial class CredentialService
{
     private IPlatformParameters PlatformParameters => new PlatformParameters(PromptBehavior.Always, false);
}

In order to register the CredentialService with the DI framework, we just need to add a small bit of code to the Initialize method of the App class in the Core library

public override void Initialize()
{
     CreatableTypes()
         .EndingWith(“Service”)
         .AsInterfaces()
         .RegisterAsLazySingleton();


    RegisterAppStart<MainViewModel>();
}

The last step is to make use of the service in the MainViewModel. We do this by adding a parameter of type ICredentialService to the MainViewModel constructor.

private ICredentialService CredentialService { get; }
public MainViewModel(ICredentialService credentialService)
{
     CredentialService = credentialService;
}


private async Task Authenticate()
{
     Debug.WriteLine(await CredentialService.Authenticate());
}

And that’s it – we haven’t changed any functionality but the solution is better organised and structured in a way that services can easily be added without cluttering up view models.

image