Setup & Use Autofac in Xamarin.Forms
Tags: xamarin, autofac
Published: 2020-07-08 08:44:51

# What is Autofac?

According to [https://autofac.org/](https://autofac.org/):
Autofac is an addictive Inversion of Control container for .NET Core, ASP.NET Core, .NET 4.5.1+, Universal Windows apps, and more.

Here are some simple steps to setup Autofac in Xamarin.Forms. 

Let me know if you found it useful.

Once, you have created a new Xamarin.Forms project with Shell template continue with the following steps:

# Manage NuGet Packages for the Xamarin.Forms library

* Select the `Browse` tab and search for `Autofac` (Author(s): Autofac Contributors)
* Get the latest stable version and select `Install`
* `Commit`

# Bootstrap

* Add new folder `Bootstrap` in Xamarin.Forms library
* Create new class `AppContainer` in this new `Bootstrap` folder
* Add `using Autofac;`
* Implement an `AppContainer` class. This example shows how to register types for the builder as single instances. Use your types, of course.
* `Commit`
* If you add or change the view models, don't forget to adapt `AppContainier` class accordingly.

```csharp
public class AppContainer
    {
        private static IContainer container;

        public AppContainer()
        {
            // services
            var builder = new ContainerBuilder();
            builder.RegisterType<NavigationService>().As<INavigationService>().SingleInstance();
            builder.RegisterType<DialogService>().As<IDialogService>().SingleInstance();
            builder.RegisterType<RepositoryService>().As<IRepositoryService>().SingleInstance();
            builder.RegisterType<PreferenceService>().As<IPreferenceService>().SingleInstance();

            // view models
            builder.RegisterType<MainViewModel>().SingleInstance();
            builder.RegisterType<ActivitiesViewModel>().SingleInstance();
            builder.RegisterType<ActivityRecordViewModel>().SingleInstance();
            builder.RegisterType<HistoryViewModel>().SingleInstance();

            container = builder.Build();
        }

        public T Resolve<T>() => container.Resolve<T>();

        public object Resolve(Type type) => container.Resolve(type);
    }
```

# How to implement ViewModelLocator

`ViewModelLocator` is a class that creates `ViewModel` classes and wires them together with `View` classes: 
* Wiring is based on the naming convention where `Views` are located in `.Views.` namespace, `ViewModels` ends with suffix `ViewModel` and Views are named with suffix `View` (e.g., ItemsView, ItemsViewModel). 
* `AutoWireViewModelProperty` is used to enable this auto wiring for the `View`. 
* Make sure that your View XAML files and classes are renamed accordingly. (ItemsPage to ItemsView). 
* Register `ViewModel` type in the `AppContainer` class (e.g., `ItemsViewModel`)

Here is an example implementation:

```csharp
public static class ViewModelLocator
    {
        private static readonly AppContainer Container;

        static ViewModelLocator() => Container = new AppContainer();

        public static readonly BindableProperty AutoWireViewModelProperty =
            BindableProperty.CreateAttached(
                "AutoWireViewModel",
                typeof(bool),
                typeof(ViewModelLocator),
                default(bool),
                propertyChanged: OnAutoWireViewModelChanged);

        public static bool GetAutoWireViewModel(BindableObject bindable) =>
            (bool)bindable.GetValue(AutoWireViewModelProperty);

        public static void SetAutoWireViewModel(BindableObject bindable, bool value) =>
            bindable.SetValue(AutoWireViewModelProperty, value);

        public static T Resolve<T>() where T : class => Container.Resolve<T>();

        private static async void OnAutoWireViewModelChanged(BindableObject bindable, object oldValue, object newValue)
        {
            if (!(bindable is Element view))
            {
                return;
            }

            var viewType = view.GetType();
            var viewName = viewType.FullName.Replace(".Views.", ".ViewModels.");
            var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
            var viewModelName = $"{viewName}Model, {viewAssemblyName}";

            var viewModelType = Type.GetType(viewModelName);
            if (viewModelType != null)
            {
                var viewModel = Container.Resolve(viewModelType) as ViewModel;
                if (viewModel != null)
                {
                    await viewModel.Initialize(null);
                }
                view.BindingContext = viewModel;
            }
        }
    }
```

# Enable AutoWire in View

`xmlns:vm="clr-namespace:YourNamespace.ViewModels;assembly=YourAssembly"`

`vm:ViewModelLocator.AutoWireViewModel="True"`

Other handy classes:

# ViewModel base class

```csharp
    public class ViewModel : Observable
    {
        public ViewModel()
        {
            NavigationService = ViewModelLocator.Resolve<INavigationService>();
            DialogService = ViewModelLocator.Resolve<IDialogService>();
            RepositoryService = ViewModelLocator.Resolve<IRepositoryService>();
            PreferenceService = ViewModelLocator.Resolve<IPreferenceService>();
        }

        protected INavigationService NavigationService { get; }
        protected IDialogService DialogService { get; }
        protected IRepositoryService RepositoryService { get; }
        protected IPreferenceService PreferenceService { get; }

        public virtual Task Initialize(object parameter) => Task.CompletedTask;
        public virtual Task Initialize() => Initialize(null);
    }
```

# Observable base class

```csharp
public class Observable : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => 
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
```

# BusyViewModel class

A Busy property can be useful to indicate loading behavior in the View for progress indicator, etc.

```csharp
public class BusyViewModel : ViewModel
    {
        private bool isBusy;

        public bool IsBusy
        {
            get => isBusy;
            set
            {
                if (value == isBusy) return;
                isBusy = value;
                OnPropertyChanged();
            }
        }
    }
```