-
Notifications
You must be signed in to change notification settings - Fork 3
Understanding Dependency Injection
All service components are organized in the hierarchy. Each hierarchy level has access to all own registered dependencies as well as to all dependencies registered on the higher level.
-
host - all dependencies registered on
HostBuilder
.-
service - all dependencies registered inside
DefineStatefulService(...)
orDefineStatelessService(...)
method and above.-
event source - all dependencies registered inside
SetupEventSource(...)
method and above -
delegate - all dependencies registered inside
DefineDelegate(...)
method and above -
listener - all dependencies registered inside
DefileAspNetCoreListener(...)
,DefineRemotingListener(...)
orDefineGenericListener(...)
method and above.
-
event source - all dependencies registered inside
-
service - all dependencies registered inside
This structure allows registration of shared dependencies on the higher level and their propagation to lower levels. This is called Hierarchical Dependencies Registration.
Imagine the following example:
You want to create a stateful service with two endpoints (ASP.NET Core and Remoting) and configure a background job. All these components should have access to same singleton instance of the ISingletonService
and have a separate instances of IScopedService
and ITransientService
.
Here is how this can be implemented it without Hierarchical Dependencies Registration:
var singleton = new SingletonService();
new HostBuilder()
.ConfigureServices(
services =>
{
services.AddScoped<IScopedService, ScopedService>();
services.AddTransient<ITransientService, TransientService>();
services.AddSingleton(singleton);
})
.DefineStatefulServiceHost(
serviceBuilder =>
{
serviceBuilder
.DefineDelegate(
delegateBuilder =>
{
delegateBuilder.ConfigureDependencies(
dependencies =>
{
dependencies.AddScoped<IScopedService, ScopedService>();
dependencies.AddTransient<ITransientService, TransientService>();
dependencies.AddSingleton(singleton);
});
})
.DefineAspNetCoreListener(
listenerBuilder =>
{
listenerBuilder.ConfigureWebHost(
webHostBuilder =>
{
webHostBuilder.ConfigureServices(
services =>
{
services.AddScoped<IScopedService, ScopedService>();
services.AddTransient<ITransientService, TransientService>();
services.AddSingleton(singleton);
})
});
})
.DefineRemotingListener(
listenerBuilder =>
{
listenerBuilder.ConfigureDependencies(
dependencies =>
{
dependencies.AddScoped<IScopedService, ScopedService>();
dependencies.AddTransient<ITransientService, TransientService>();
dependencies.AddSingleton(singleton);
});
});
})
.Build();
While this implementation has a lot of duplications it still works. But what if implementation of ISingletonService
has dependencies? Imaging the implementation of ISingletonService
depends on the IConfiguration
or IHostedEnvironment
services configured by HostBuilder
. In this case we can't instantiate ISingletonService
as before.
Let's see how this can be implement with Hierarchical Dependencies Registration:
new HostBuilder()
.ConfigureServices(
services =>
{
services.AddScoped<IScopedService, ScopedService>();
services.AddTransient<ITransientService, TransientService>();
services.AddSingleton<ISingletonService, SingletonService>();
})
.DefineStatefulServiceHost(
serviceBuilder =>
{
serviceBuilder
.DefineDelegate(delegateBuilder => { ... })
.DefineAspNetCoreListener(listenerBuilder => { ... })
.DefineRemotingListener(listenerBuilder => { ... });
})
.Build();
That's it.
Here are important internal details about Hierarchical Dependencies Registration:
- All components have own dependency injection container. The
singleton
services are proxied whilescoped
andtransient
services are re-registered. - Dependency registration isn't proxied or re-registered if same dependency is registered on the lower level:
new HostBuilder() .ConfigureServices( services => { services.AddTransient<ITransientService, RootTransientService>(); }) .DefineStatefulServiceHost( serviceBuilder => { serviceBuilder .ConfigureDependencies( dependencies => { // All lower levels will now have LocalTransientService // implementation instead of RootTransientService. services.AddTransient<ITransientService, LocalTransientService>(); }); }) .Build();
- The dependencies of the following types aren't proxied or re-registered:
IHostedService
There are multiple dependencies registered automatically by the infrastructure on all hierarchy levels.
These dependencies are accessible in both stateful and stateless services:
These dependencies are specific to stateful service:
-
StatefulServiceContext same instance as
ServiceContext
. -
IStatefulServicePartition same instance as
IServicePartition
. - IReliableStateManager
These dependencies are specific to stateless service:
-
StatelessServiceContext same instance as
ServiceContext
. -
IStatelessServicePartition same instance as
IServicePartition
.
There is no special built-in dependencies registered for event source.
These dependencies are accessible in both stateful and stateless services:
-
IServiceEventSource
(and all specialized interfaces)public interface IServiceEventSource { void WriteEvent<T>( ref T eventData) where T : ServiceEventSourceData; }
These dependencies are specific to stateful service:
-
IStatefulServiceDelegateInvocationContext
public interface IStatefulServiceDelegateInvocationContext { StatefulServiceLifecycleEvent Event { get; } }
These dependencies are specific to stateless service:
-
IStatelessServiceDelegateInvocationContext
public interface IStatelessServiceDelegateInvocationContext { StatelessServiceLifecycleEvent Event { get; } }
These dependencies are accessible in all listeners:
-
IServiceEventSource
(and all specialized interfaces)public interface IServiceEventSource { void WriteEvent<T>( ref T eventData) where T : ServiceEventSourceData; }
-
IServiceHostListenerInformation
public interface IServiceHostListenerInformation { string EndpointName { get; } }
These services are specific to ASP.NET Core listeners:
-
IServiceHostAspNetCoreListenerInformation
public interface IServiceHostAspNetCoreListenerInformation : IServiceHostListenerInformation { // The URL suffix set by Service Fabric middleware // when setting UseUniqueServiceUrlIntegration() is on. string UrlSuffix { get; } }
These services are specific to Remoting listeners:
-
IServiceHostRemotingListenerInformation
public interface IServiceHostRemotingListenerInformation : IServiceHostListenerInformation { }
These services are specific to Generic listeners:
-
IServiceHostGenericListenerInformation
public interface IServiceHostGenericListenerInformation : IServiceHostListenerInformation { }
(c) 2021 Coherent Solutions Inc.
GENERAL
GETTING STARTED
UNDERSTANDING THE PROJECT
SAMPLES