Dependency Injection in WPF Application using Generic HostBuilder
In this post, we shall learn how to perform dependency injection in the WPF application using Generic HostBuilder in .NET Core.
We already learned how to leverage the Generic Host Builder approach for .NET Core-based applications like Console application and Windows Forms Application in our previous post.
DI is a simple and impressive concept where you inject and use the services that you need, making your application highly efficient and lightweight.
Today in this article, we will cover below aspects,
As already discussed in our previous article, there are multiple benefits of the DI(Dependency Injection) approach like,
-Separation of concern
-Independently deployable unit
-Easily Testable units
-High performance
-Easy maintenance
Getting started
Here I am using a WPF (Windows Presentation Foundation) .NET Core 3.1 or .NET 5.0 project template,
Creating Generic HostBuilder
Generic HostBuilder in .NET Core was introduced in .NET Core 2.1 release and designed to be used for both Non-HTTP and HTTP workloads. So we shall try attempting to use it for the non-host WPF applications today.
Please install the NuGet package from Nuget Package manager or PMC,
PM> Install-Package Microsoft.Extensions.Hosting -Version 3.1.2
The HostBuilder class is available from the following namespace,
using Microsoft.Extensions.Hosting;
HostBuilder implements the IHostBuilder interface.
Please create Generic HosBuilder and register the dependencies that need to inject.
In the WPF application, we shall use App.XAML as an entry point to set up the IoC container.
Initialize the Host
Within Constructor of App class(file: App.XAML.cs) please add the below code to build Host,
host = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
}).Build();
OR
By using generic host builder CreateDefaultBuilder
host = Host.CreateDefaultBuilder()
.ConfigureServices((hostContext, services) =>
{
}).Build();
DI Container
We shall be injecting EmployeeWindow and EmployeeViewModelobject for more precise results,
host = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
//Add business services as needed
services.AddScoped<IEmployeeViewModel, EmployeeViewModel>();
//Lets Create single tone instance of Master windows
services.AddSingleton<EmployeeWindow>();
}).Build();
Here we are considering EmployeeWindow as the main Window that will be an entry point for workflow and business functionalities.
You are free to add an additional layer separating actual UI components if needed.
All the services registered using HostBuilder will be available to use as per need. The lifetime management of those services will be taken care of by the IoC container and we need not have disposed of them explicitly.
EmployeeWindow implementation is as below. Here EmployeeViewModel is DI using Constructor Injection.
IEmployeeViewModel Interface definition as below,
public interface IEmployeeViewModel
{
string GetEmployeeDetails();
}
EmployeeViewModel implementation as below,
public class EmployeeViewModel : IEmployeeViewModel
{
public EmployeeViewModel()
{
}
public string GetEmployeeDetails()
{
string FirstName = "TheCode";
string LastName = "Buzz";
return $"Employee Name is: {FirstName} {LastName} ";
}
}
Let’s execute the application and try button click action,
App.xaml file used for above code as below,
Please make a note I have commented on the line which set up StartupUri.
<Application x:Class="WPFDesktopApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--StartupUri="MainWindow.xaml"-->
<Application.Resources>
</Application.Resources>
</Application>
Setting up OnStartup and OnExit Application events
If needed you can set up Setting up OnStartup and OnExit Application events as below,
private void OnStartup(object sender, StartupEventArgs e)
{
var mainWindow = host.Services.GetService<EmployeeWindow>();
mainWindow.Show();
}
Similarly, the OnExit event can be defined as below,
protected override async void OnExit(ExitEventArgs e)
{
using (host)
{
await host.StopAsync();
}
base.OnExit(e);
}
App.XAML file used as below,
<Application x:Class="WPFDesktopApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="OnStartup">
<Application.Resources>
</Application.Resources>
</Application>
If interested to know on one more approach, please see below post,
Do you know you can create a host builder using generic host builder CreateDefaultBuilder a .NET and ASP.NET Core? It helps us to provide accessing application configuration, user secretes, getting access to environmental information by default out of the box.
Can we make the above code better?
Please let me know if you have any better suggestions. Please sound off your comments below.
Summary
Today we learned one more approach for leveraging the Dependency Injection (DI) in WPF (Windows Presentation Foundation) applications based on the .NET Core framework. We learned that using Hostbuilder we can easily leverage DI applications and can create highly maintainable and extensible Desktop applications.
Please bookmark this page and share it with your friends. Please Subscribe to the blog to receive notifications on freshly published(2024) best practices and guidelines for software design and development.
Thanks for posting this. Numerous other articles about this neglect to store the IHost in a module variable and shut it down on Exit. I was mindlessly disposing the host like in a web or console app and getting errors using the service container subsequent to startup. This pointed me in the right direction for the fix. Thanks!
Hey Larrold – Thanks for the feedback. Glad to know the article helped you!
Let me give object instances a number for my example:
So you open Scope1, request your singleton EmployeeWindow with a scoped ViewModel1.
If you now leave Scope1, open up a Scope2 and again request your singleton EmployeeWindow, will it still have ViewModel1 (because that object instance was used to instantiate your Window that since then still lives unchanged)? Or do you suppose it to get a new ViewModel2 because ViewModel is scoped and you are now in Scope2?
So do you think injecting a scoped object into a singleton is good practice?
what are your thoughts re using Generic HostBuilder vs Autofac for Dependency Injection in a WPF application?
Hey JPort, I see as long as the framework provided a generic host builder serves all the use cases we can simply use it. If we see any challenges or limitations then Autofac is a good alternate too. Again these are just my thoughts. Let me know your analysis/inputs if any.
Why are you stopping the host?
using (host)
{
await host.StopAsync();
}
It was never started.
Hello Dermot – Thanks for your query. I gave those as examples on we can handle the start and stop event mainly used for initializing or garbage of unmanaged resources if any. However, when you call the Build method on the builder.Build() it does initialize/start the host once. Another preferred method for the console app is to use UseConsoleLifetime() method which initiates the shutdown process by calling StopApplciation()
Hope this helps.
This requires a change to the App.xaml file (change StarupURI= to Start=”OnStartup” for this to work.
Thank you Tom for the inputs. Appreciate that! I Updated the section with details using OnStartup and OnExit application life cycle events
Thanks . This was unique and very useful to me.