Dependency injection in xamarin form using AutoFac

Brief: Here we will learn how to add constructor Dependency Injection in xamarin.form using AutoFac

What is Dependency injection?
Before getting into any definition let us look into a simple example, For xamarin form application
whenever we need to get the native functionalities ( Check internet connectivity, Location,Camera
and any device details etc) Dependency injection is the best way to get the solution.


In below example shown how to launch phone dialer from xamarin form project. 

//xamarin form project (PCL or standard .Net)-define interface
public interface IDialer
{
bool Dial(string number);
}
//android interface implementation
[assembly: Xamarin.Forms.Dependency(typeof(PhoneDialer))]
namespace Sample.Mobile.Droid.Helper
{
public class PhoneDialer : IDialer
{
public void Dial(string number)
{
var intent = new Intent(Intent.ActionDial);
intent.SetData(Android.Net.Uri.Parse("tel:" + number));
StartActivity(intent);
}
}
}
//ios interface implementation
[assembly: Xamarin.Forms.Dependency(typeof(PhoneDialer))] //DI Registration
namespace Sample.Mobile.iOS.Helper
{
public class PhoneDialer : IDialer
{
public void Dial(string number)
{
UIApplication.SharedApplication.OpenUrl( new NSUrl("tel:" + number));
}
}
}
//xamarin form project- call to dependency service method
private void Call(string PhoneNumber)
{
var dialer = DependencyService.Get<IDialer>().Dial(PhoneNumber);
}
In the above example, line no: 38 "DependencyService.Get<IDialer>().Dial(PhoneNumber)" here dependencies i.e. actual implementation of dialer functionality will be injected during runtime. Here PCL or .Net Standard project doesn’t know anything about implementation or the platform which provides implementation.

This is what dependency injection is and this is not all about dependency injection. What xamarin.form provides dependency injection is a limited version and it doesn't support the important feature like constructor injection. There are few frameworks like Autofac,Unity,..etc which does support this feature.

Dependency injection is a process by which dependencies or required functionalities will be
unknown(abstract) and it will be injected only during runtime.
Or
As per Microsoft document definition:
Dependency injection is a specialized version of the Inversion of Control (IoC) pattern, where the concern being inverted is the process of obtaining the required dependency. With dependency injection, another class is responsible for injecting dependencies into an object at runtime. (Link)

The class that's responsible for instantiating the interface object, and inserting it into the class, is known as the dependency injection container.

Here container is responsible for mapping to the implementation and providing the implementation
during the runtime, this is also called as Register and Resolve in dependency injection.

Why Dependency injection?
Dependency injection helps to achieve the Decoupling within the project solution.
This is the one of the programming standard that enhances the code readability. Decoupling between the concrete type and the code that makes use of this concrete type. Concrete type is the one that extends this interface and implements the functionality. DI Provides the plug and play feature for the project components.

Example : In Car parts, if battery stopped working suddenly then now I can change the current battery with any other battery, any brand without changing anything in the other car parts. Here change is just a battery. As soon as connecting new battery, car should start working.
Same way in my project later some time if i want to change my data layer with different
data provider then i can do that without any changes to the main project.

Now let us directly jump in to the coding part.
Project structure :

Add NugetPackage:
Xamarin Form .Net standard project added with two nuget packages "AutoFac" and "AutoFac.Extras.Common.ServiceLocator".

Add New project(.Net standard library) "ServiceManager" for data layer and referenced the same in main project.
Create EmployeeService.cs by returning some random employee name list. In real time scenario data will be fetched from the server via web service request here for illustration purpose some static data used.
using System;
using System.Collections.Generic;
namespace ServiceManager
{
public class EmployeeService : IEmployeeService
{
public EmployeeService()
{
}
/// <summary>
/// get employee name mock data
/// </summary>
/// <returns></returns>
public List<string> GetEmployeeNameList()
{
var list = new List<string>
{
"Shravan Madavu",
"Joshi naveen",
"Kotte Jayan",
"Ravi naganna",
"Kiran kumar",
"Elicia Esposito",
"Vivien Perras"
};
return list;
}
}
}
using System.Collections.Generic;
namespace ServiceManager
{
public interface IEmployeeService
{
List<string> GetEmployeeNameList();
}
}

Create container class AutoFacContainer.cs by mentioning the required registrations
public sealed class AutoFacContainer
{
public static void Initialize()
{
ContainerBuilder containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<MainPageViewModel>().AsSelf();
containerBuilder.RegisterType<EmployeeService>().As<IEmployeeService>();
IContainer container = containerBuilder.Build();
AutofacServiceLocator autofacServiceLocator = new AutofacServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => autofacServiceLocator);
}
}

Create UI xaml file MainPage.xaml to show employee name list
<?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:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="SampleAutoFacDI.MainPage"
BindingContext="{Binding MainPageViewModel,Source= {StaticResource Locator}}">
<StackLayout>
<ListView ItemsSource="{Binding EmployeeCollection}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10">
<Label Text="{Binding}" FontSize="Medium"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
view raw MainPage.xaml hosted with ❤ by GitHub

Initialize the container and locater class ViewModelLocator.cs as follows

using CommonServiceLocator;
namespace SampleAutoFacDI.ViewModels
{
public class ViewModelLocator
{
static ViewModelLocator()
{
AutoFacContainer.Initialize();
}
public MainPageViewModel MainPageViewModel
{
get
{
return ServiceLocator.Current.GetInstance<MainPageViewModel>();
}
}
}
}
Change the App.xaml to update the ResourceDictionary with locater key value
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:vm="clr-namespace:SampleAutoFacDI.ViewModels"
x:Class="SampleAutoFacDI.App">
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator"/>
</ResourceDictionary>
</Application.Resources>
</Application>
view raw App.xaml hosted with ❤ by GitHub

Create View model class MainPageViewModel.cs, here the constructor is injected with service data.
using System.Collections.ObjectModel;
using ServiceManager;
namespace SampleAutoFacDI.ViewModels
{
public class MainPageViewModel
{
private readonly IEmployeeService _employeeService;
private ObservableCollection<string> _employeeCollection;
public ObservableCollection<string> EmployeeCollection
{
get
{
return _employeeCollection;
}
}
public MainPageViewModel(IEmployeeService employeeService)//Injected service data here
{
_employeeService = employeeService;
InitializeData();
}
private void InitializeData()
{
var empList = _employeeService.GetEmployeeNameList();
_employeeCollection = new ObservableCollection<string>();
empList.ForEach(emp => _employeeCollection.Add(emp));
}
}
}

You can clone the project code from github link.

Follow our FB page for the latest blog post updates. Keep visiting :) and Happy coding!.

No comments:

Post a Comment