Dependency Injection
Services and Dependency Injection in 3.1.
Starting with Wisej.NET 3.1 we added full support for services and dependency injection. Like everything else in Wisej.NET, it's a very lean, performant, and flexible implementation.
If you need something more complex, we also support switching our IServiceProvider with any third party implementation, including Microsoft's DI, Autofac or others.
Our DI implementation is supported in both .NET 4.8 and .NET Core.
Registering Services
You can register services at any point in the application. Services are always registered globally so if a service type is registered more than once, subsequent definitions will replace the existing definition.
A good place to initialize the services in the static Program constructor. However, you can register services anywhere else in your code.
The code above registers 2 services.
One is an ILogger implementation. Wisej.NET will create an instance if MyLogger only once (Global scope) the first time it's used. This service will never be disposed, if it implements IDisposable, because it's registered using the Shared lifetime making it a singleton instance used by all sessions.
The second line registers a service of type IFileSystem and delegates the creation of the implementation to the CreateFileSystemFactory method, and sets the scope to Session. In this case, Wisej will invoke CreateFileSystemFactory the first time the service is requested per session. The service instance will be automatically disposed, if it implements IDisposable, at the end of the session.
Using a Service
Your code can request a service implementation in three ways:
Using Application.Services.GetService<T>().
Using the [Inject] attribute on a property.
Adding a service argument to the constructor of another service implementation.
Application.GetService<T>() returns the service implementation for the requested T type, if it exists, or null. You can call it at any time.
Using the [Inject] attribute works by default only on top-level UI containers: Page, Form, and Desktop classes. When you add the [Inject] attribute to a property (either protected, private or public), Wisej.NET will automatically resolve the service and assign it to the property during the construction of the object.
To use the [Inject] attribute on any object, call Application.Services.Inject(object).
Services created by Wisej.NET can receive an instance of another services simply by declaring the requested service in the constructor.
Service Injection
Wisej.NET supports Dependency Injection in two ways: Constructors and Property Injection.
Property injection is supported automatically for all top level containers (Form, Page, Desktop) and all services created by the system. Constructor injection is supported for service creation.
For example, if MyFileSystemImplementation was declared like this:
Wisej.NET automatically assigns the Logger property with the registered ILogger service instance when the service is created. Another way is to declare a custom constructor (it works only for services created by the system):
You can also inject properties into any object programmatically:
If the object declares any [Inject] properties they will receive the service instance according to the service lifetime.
Generic Service Type
You can register generic types as services (starting from Wisej.NET 3.5.4) and request the concrete service instance at runtime.
When requesting a service, Wisej.NET constructs or retrieve the correct instance of the generic type.
Alternative IServiceProvider
In case you want to use something else to manage services, simply register the other IServiceProvider object.
The line Application.AddService<IServiceProvider>(app.Services);
registers Microsoft's IServiceProvider with Wisej.NET and replaces our IServiceProvider.
From this point on, calling Application.Services.AddService<T>() is not supported, all services have to be registered using Microsoft's DI.
Application.Services.GetService<T>() and [Inject] now use the alternative IServiceProvider to resolve services. The IServiceProvider instance is registered as a global singleton by default, but you can also register it per session using a different ServiceLifetime option.
Services Lifetime
We support the following service lifetimes:
Shared: The service instance is a singleton used by all sessions and all threads.
Session: The service instance is created per session and disposed (if IDisposable) when the session ends. Note that no other DI container supports the session lifetime.
Thread: The service instance is created per thread (corresponds roughly to requests from the browser) and disposed (if IDisposable) when the thread code ends.
Transient: The service instance is created every time it's requested. It's never disposed, the responsibility of disposing (if IDisposable) is with the caller.
The default lifetime, if not specified, when registering a service is always Shared.
Last updated