After registering instances on my IServiceCollection
, I need to register an IAutomapperProvider
that depends on an IAssemblyProvider
that was registered before this method call
public static IServiceCollection RegisterAutomapperConfiguration(this IServiceCollection container, ServiceLifetime lifeTime = ServiceLifetime.Scoped)
{
//creating the provider to get the IAssemblyProvider for my IAutomapperProvider
var prov = container.BuildServiceProvider();
var assemblyProvider = prov.GetService<IAssemblyProvider>();
container.Register<IAutomapperProvider>(aProv => new AutomapperProvider(assemblyProvider), lifeTime);
var autoMapperProvider = prov.GetService<IAutomapperProvider>();
var mapperConfig = autoMapperProvider.GetMapperConfiguration();
...
}
If right after the call of container.Register<IAutomapperProvider>(aProv => new AutomapperProvider(assemblyProvider), lifeTime);
I don't call BuildServiceProvider again, then I would not get the IAutomapperProvider I registered before
public static IServiceCollection RegisterAutomapperConfiguration(this IServiceCollection container, ServiceLifetime lifeTime = ServiceLifetime.Scoped)
{
//creating the provider to get the IAssemblyProvider for my IAutomapperProvider
var prov = container.BuildServiceProvider();
var assemblyProvider = prov.GetService<IAssemblyProvider>();
container.Register<IAutomapperProvider>(aProv => new AutomapperProvider(assemblyProvider), lifeTime);
prov = container.BuildServiceProvider();
var autoMapperProvider = prov.GetService<IAutomapperProvider>();
var mapperConfig = autoMapperProvider.GetMapperConfiguration();
...
}
On the AspNetCore code when you call BuildServiceProvider extension method they use the same IServiceCollection that can change over the time adding more elements, at the end you are pointing to the same reference
public static ServiceProvider BuildServiceProvider(this IServiceCollection services)
{
return BuildServiceProvider(services, ServiceProviderOptions.Default);
}
Then why I need to call it again to get a new instance that knows how to resolve my Service?
To avoid confusions, the Register method is an extension I created but internally calls the AddSinglenton or Add...
public static IServiceCollection Register<TService>(this IServiceCollection container, Func<IServiceProvider, TService> implementationFactory, ServiceLifetime lifeTime)
where TService : class
{
if (container == null)
throw new ArgumentNullException(nameof(container));
if (implementationFactory == null)
throw new ArgumentNullException(nameof(implementationFactory));
switch (lifeTime)
{
case ServiceLifetime.Scoped:
container.AddScoped(typeof(TService), (Func<IServiceProvider, object>)implementationFactory);
break;
case ServiceLifetime.Transient:
container.AddTransient(typeof(TService), (Func<IServiceProvider, object>)implementationFactory);
break;
default:// ServiceLifetime.Singleton
container.AddSingleton(typeof(TService), (Func<IServiceProvider, object>)implementationFactory);
break;
}
return container;
}
Calling BuildServiceProvider multiple times can cause serious trouble, because each call to BuildServiceProvider results in a new container instance with its own cache. This means that registrations that are expected to have the Singleton lifestyle, suddenly are created more than once.
BuildServiceProvider(IServiceCollection, ServiceProviderOptions) Creates a ServiceProvider containing services from the provided IServiceCollection optionally enabling service-creation and scope validation.
IServiceCollection is the collection of the service descriptors. We can register our services in this collection with different lifestyles (Transient, scoped, singleton) IServiceProvider is the simple built-in container that is included in ASP.NET Core that supports constructor injection by default.
What is an IServiceProvider? The IServiceProvider is responsible for resolving instances of types at runtime, as required by the application. These instances can be injected into other services resolved from the same dependency injection container.
BuildServiceProvider
does not have to be invoked so often.
That is what the implementation factory delegates are for. They provide access to a service provider for that purpose.
It is still uncertain why you have to build the provider in the first instance but based on currently provided code use the service provider within the implementation factory delegate when registering your provider.
public static IServiceCollection RegisterAutomapperConfiguration(this IServiceCollection services,
ServiceLifetime lifeTime = ServiceLifetime.Scoped) {
services.Register<IAutomapperProvider>(p => //<-- p is IServiceProvider
//use the provider to get the IAssemblyProvider for my IAutomapperProvider
new AutomapperProvider(p.GetService<IAssemblyProvider>()), lifeTime);
prov = services.BuildServiceProvider();
var autoMapperProvider = prov.GetService<IAutomapperProvider>();
var mapperConfig = autoMapperProvider.GetMapperConfiguration();
//...
}
When BuildServiceProvider
is invoked, the created service provider will only be aware of types that were in the collection when it was built. It will not be aware of any additional types, which is why is it usually done at the end of registering all types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With