Dependency Injection
ASP.NET Core relies on the dependency injection mechanism to ensure that applications can customize the framework by implementing custom services. Bulletcode.NET takes advantage of this by re-implementing some of the core ASP.NET services, but it also allows applications to customize its own services. To make this possible, both ASP.NET and Bulletcode.NET use the TryAdd()
family of methods to register their services whenever possible.
Bulletcode.NET also relies on dependency injection in desktop applications. View models are created using the service provider, which means that dependencies can be injected into them, and their lifetime is scoped to the lifetime of the corresponding page or dialog in the UI. More information can be found in the MVVM chapter.
Built-in services
The following extension methods for registering Bulletcode.NET services are available in web applications:
AddConfiguration()
— see ConfigurationAddCoreMvcServices()
andAddFrontViewServices()
— see MVCAddUserCookie()
,AddUserToken()
andAddApiKey()
— see AuthenticationAddRoleBasedAuthorization()
— see AuthorizationAddUserService()
andAddEventService()
— see DatabaseAddSqlSession()
— see SessionAddMailService()
— see MailAddStorageService()
— see Storage
The following extension methods are available in desktop applications:
AddTransations()
,AddLanguageOptions()
— see InternationalizationUseApplication()
,UseMainWindow()
andAddNavigationProvider()
— see ShellAddExceptionHandler()
— see DiagnosticsRegisterDesktopServices()
— see ServicesAddApiClient()
— see API Client
Service attributes
To make it easier to register custom services, you can use the following attributes: Singleton
, Transient
and Scoped
. By default, the service type is the same as the implementation type decorated by one of these attributes:
[Singleton]
public class MyService
{
}
It is also possible to specify a custom service type used to access the service, for example:
[Singleton( typeof( IMyService ) )]
public class MyService : IMyService
{
}
If the AllowMultiple
property of the service attribute is set to true
, the service is registered by calling TryAddEnumerable
instead of TryAdd
, which means that multiple implementations of the same service can exist.
In order to register all services decorated with the service attributes, call the RegisterServices()
extension method, passing the assembly containing the types to register, for example:
services.RegisterServices( typeof( Program ).Assembly );
Service aliases
The AddAlias<TService, TImplementation>()
extension method makes it possible to register a class which implements two or more different services:
public class MyService : IMyService, IMyDataProvider
{
}
Normally, when you register such class as a singleton, two separate instances of the MyService
class are created for each interface. To solve this problem, you can register the second service as an alias, which means that both services will share the same instance of the MyService
class:
services.AddSingleton<IMyService, MyService>();
services.AddAlias<IMyDataProvider, MyService>();
AddAlias()
can also be used for scoped services; in this case, both services will share the same instance in a given score. Aliases cannot be used for transient services.
Aliases can be added for services registered using the Singleton
or Scoped
attributes, by adding one or more Alias
attributes:
[Singleton( typeof( IMyService ) )]
[Alias( typeof( IMyDataProvider ) )]
public class MyService : IMyService, IMyDataProvider
{
}
IScopedServiceFactory
ASP.NET Core supports scoped services whose lifetime is bound to a particular web requests. A similar mechanism is also implemented by Bulletcode.NET to bind the lifetime of view models and their dependencies to a particular page or dialog in a desktop application. Internally, this mechanism uses the IScopedServiceFactory
, which contains a method for creating an instance of the specified type and its dependencies within its own scope, and to destroy the service together with its scope.
In order to use the IScopedServiceFactory
to create custom scopes, call the AddScopedServiceFactory()
extension method.