Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

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<IAuthenticationHttpMessageHandler, AuthenticationHttpMessageHandler>();
     containerRegistry.RegisterSingleton<IAuthenticatedHttpClientService, AuthenticatedHttpClientService>();
     containerRegistry.RegisterInstance<ILazyDependency<IUserService>>(
         new LazyDependency<IUserService>(() =>
         RestService.For<IUserService>(
             PrismApplicationBase.Current.Container.Resolve<IAuthenticatedHttpClientService>().AuthenticatedHttpClient)
         ));
}

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

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

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