Home > front end >  Injecting services into view models in .NET MAUI app
Injecting services into view models in .NET MAUI app

Time:05-31

I'm trying to understand how to implement dependecy injection in a .NET MAUI app.

I have a service class -- and its interface -- that handle my REST calls that looks like this:

public class MyRestApiService : IMyRestApiService
{
   public async Task<string> Get()
   {
      // Do someting
   }
}

I then place this in my DI container in MauiProgram.cs:

builder.Service.AddTransient<IMyRestApiService, MyRestApiService>();

I also have a view model that I will use for my MainPage.xaml. The question is, if I do a constructor injection of my service, the XAML doesn't seem to like it.

The MainPageViewModel looks like this:

public class MainPageViewModel : BaseViewModel
{
   IMyRestApiService _apiService;
   public MainPageViewModel(IMyRestApiService apiService)
   {
      _apiService = apiService;
   }
}

When I tried to define MainPageViewModel as the view model for MainPage.xaml as below, I get an error:

<ContentPage.BindingContext>
   <vm:MainPageViewModel />
</ContentPage.BindingContext>

The error reads:

Type MainPageViewModel is not usable as an object element because it is not public or does not define a public parameterless constructor or a type converter.

How do I inject my services into my view models?

CodePudding user response:

You will want to resolve everything basically from the first page for everything to fall in place and for dependency injection to work.

Have a look at this example: https://github.com/jfversluis/MauiDependencyInjectionSample

You will want to register your services, view models and views. In your case, in your MauiProgram.cs add:

// Change scopes as needed, this seems to make sense
builder.Service.AddTransient<MainPage>();
builder.Service.AddTransient<MainPageViewModel>();
builder.Service.AddSingleton<IMyRestApiService, MyRestApiService>();

Then in your App.xaml.cs also start injecting your (main) page:

public partial class App : Application
{
    public App(MainPage page)
    {
        InitializeComponent();

        MainPage = page;
    }
}

Now in your MainPage.xaml.cs add a constructor like this:

public LoginPage(MainPageViewModel viewModel)
{
    InitializeComponent();

    BindingContext = viewModel;
}

From there everything should follow suit and be connected. What you are trying to do with

<ContentPage.BindingContext>
   <vm:MainPageViewModel />
</ContentPage.BindingContext>

Is basically setting the BindingContext through the property. You can, but then you'll have to specify the parameters yourself and resolve them from the dependency injection container somehow which typically you don't want to do.

CodePudding user response:

To inject your view model into your view you actually need to do it in its constructor, in code behind, like this:

public partial class LoginPage : ContentPage {
    public LoginPage(ILoginViewModel loginViewModel) {
        BindingContext = loginViewModel;
        InitializeComponent();
    }
}

Also you have to register views that use dependency injection:

builder.Service.AddTransient<LoginPage>();

Afaik you can't instantiate a view model with DI in XAML like you are doing

  • Related