I'm using Simple Injector. I have a background processor which is using DI from the start. It will pickup jobs to run, and run them. However, each job needs to run within its own scope so that I can override some contextual dependencies. For example, the job needs to run within a specific security context (the one from which it was created), so I need to start a new scope and override the ISecurityContext injection so the job will be properly secured.
To accomplish this, I was creating a new container (with the proper ISecurityContext) and starting a scope, then running the job, but I'm not sure if this is an appropriate thing to do.
RunJob
private readonly Func<ISecurityContext, Container> _containerFactory;
internal async Task RunJob(BackgroundJob job) {
var parameters = job.GetParameters();
var securityContext = parameters.SecurityContext;
using (var container = _containerFactory(securityContext))
using (AsyncScopedLifestyle.BeginScope(container)) {
// Run the job within this scope.
}
}
DI Bits
container.RegisterSingleton<Func<ISecurityContext, Container>>(() => securityContext => {
var c = new Container();
RegisterDependencies(c);
c.Options.AllowOverridingRegistrations = true;
c.Register<ISecurityContext>(() => securityContext, Lifestyle.Scoped);
return c;
});
It doesn't feel right to me, but I'm not sure what the correct solution is.
The Simple Injector documentation warns about what you are doing by stating:
Warning: Do not create an infinite number of Container instances (such as one instance per request). Doing so will drain the performance of your application. The library is optimized for using a very limited number of Container instances. Creating and initializing Container instances has a large overhead, but resolving from the Container is extremely fast once initialized.
In general, you should create only one Container instance per application. This not only holds from a performance perspective, but the creation of this sort of 'child containers' in general is littered with quirks and flaws. For instance, how to ensure that registrations are singletons across the application?
So instead, don't abuse the container for your runtime state, but store it elsewhere. You can use a Scope instance as dictionary for scoped state, but it's as easy to create a simple wrapper for ISecurityContext that is registered as Scoped instance and gets initialized directly after the scope is created as seen in the following example.
// Can be part of your Composition Root
internal sealed class SecurityContextWrapper : ISecurityContext
{
// One of the rare cases that Property Injection makes sense.
public ISecurityContext WrappedSecurityContext { get; set; }
// Implement ISecurityContext methods here that delegate to WrappedSecurityContext.
}
// Composition Root. Only have 1 container for the complete application
c = new Container();
RegisterDependencies(c);
c.Register<SecurityContextWrapper>(Lifestyle.Scoped);
c.Register<ISecurityContext, SecurityContextWrapper>(Lifestyle.Scoped);
// Job logic
private readonly Container _container;
internal async Task RunJob(BackgroundJob job) {
var parameters = job.GetParameters();
var securityContext = parameters.SecurityContext;
using (AsyncScopedLifestyle.BeginScope(_container)) {
// Resolve the wapper inside the scope
var wrapper = _container.GetInstance<SecurityContextWrapper>();
// Set it's wrapped value.
wrapper.WrappedSecurityContext = securityContext;
// Run the job within this scope.
}
}
Alternatively, if you use Scope as state, you can inject a Scope instance as constructor argument of SecurityContextWrapper. That removes the need to use Property Injection, but does make your SecurityContextWrapper dependent on Simple Injector:
// Can be part of your Composition Root
internal sealed class SecurityContextWrapper : ISecurityContext
{
ISecurityContext _wrappedSecurityContext;
public SecurityContextWrapper(Scope scope)
{
_wrappedSecurityContext= (ISecurityContext)scope.GetItem(typeof(ISecurityContext));
}
// Implement ISecurityContext methods here that delegate to WrappedSecurityContext.
}
// Composition Root. Only have 1 container for the complete application
c = new Container();
RegisterDependencies(c);
c.Register<ISecurityContext, SecurityContextWrapper>(Lifestyle.Scoped);
// Job logic
private readonly Container _container;
internal async Task RunJob(BackgroundJob job) {
var parameters = job.GetParameters();
var securityContext = parameters.SecurityContext;
using (var scope = AsyncScopedLifestyle.BeginScope(_container)) {
// Set it's wrapped value.
scope.SetItem(typeof(ISecurityContext), securityContext);
// Run the job within this scope.
}
}
Related
I have one dependency registered as follows:
interface IDependency { }
class DependencyImpl : IDependency { }
Startup:
services.AddScoped<IDependency, DependencyImpl>();
This works as intendended as I do want to reuse the same instance in the scope of my Web API requests.
However, in one background service, I'd like to tell which instance it will resolve to:
class MyBackgroundService
{
private readonly IServiceScopeFactory _scopeFactory; // set in ctor
public void DoStuff()
{
var itens = GetItens();
var dependencyInstance = new DependencyImpl();
Parallel.ForEach(itens, (item) =>
{
using(var scope = _scopeFactory.CreateScope())
{
scope.SwapDependencyForThisScopeOnly<IDependency>( () => dependencyInstance ); // something like this
var someOtherService = scope.ServiceProvider.GetRequiredService<ItemService(); // resolve subsequent services with provided dependencyInstance
someOtherService.Process(item);
}
});
}
}
I can't reuse the same Scope because ItemService (and/or it's dependencies) uses other scoped services that can't be shared. Neither I want to replace dependency resolution for the entire application.
Is it possible to do what I want here? Does it make sense?
I'm using dotnet core 2.2 with default IoC container for that matters.
Edit in reply to #Steven: DependencyImpl contains configurations for how an item will be processed. One of those includes an relatively expensive query. DependencyImpl is also injected more than once in the graph. So, currently, it reads the configuration once, cache them in private properties, and use the cached version on subsequent reads. Because I know I'll be reusing the same configuration for all itens here, I'd like to avoid reading the configuration again for each parallel execution.
My real-world dependency is more similar to this:
interface IDependency
{
Task<Configuration> GetConfigurationAsync();
}
class DependencyImpl : IDependency
{
private readonly Configuration _configuration;
private readonly DbContext _dbContext;
ctor(DbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<Configuration> GetConfigurationAsync()
{
if(_configuration is null)
{
// read configurations
}
return _configuration;
}
}
I understand that, as is, my class is not thread-safe. I'd have to force a read at the start and/or add some thread safety here.
Also, those processings used to happen during the lifetime of a web request, and the background service is the new stuff. I'd prefer to change as little of existing code as possible, because there are few tests in place, and of course time constraints from the powers-that-be.
In general, it is not a good idea to change the structure of the registered object graphs while the application is running. Not only is this hard to achieve with most containers, it is prone to suble problems that are hard to detect. I, therefore, suggest a small change in your design that change circumvents the problem you are facing.
Instead of trying to change the dependency as a whole, instead pre-populate an existing dependency with the data loaded on a a different thread.
This can be done using the following abstraction/implementation pair:
public interface IConfigurationProvider
{
Task<Configuration> GetConfigurationAsync();
}
public sealed class DatabaseConfigurationProvider : IConfigurationProvider
{
private readonly DbContext _dbContext;
public DatabaseConfigurationProvider(DbContext dbContext)
{
_dbContext = dbContext;
}
public Configuration Configuration { get; set; }
public async Task<Configuration> GetConfigurationAsync()
{
if (Configuration is null)
{
await // read configurations
}
return Configuration;
}
}
Notice the public Configuration on the DatabaseConfigurationProvider implementation, which is not on the IConfigurationProvider interface.
This is the core of the solution I'm presenting. Allow your Composition Root to set the value, without polluting your application abstractions, as application code doesn't need to overwrite the Configuration object; only the Composition Root needs to.
With this abstraction/implementation pair, the background service can look like this:
class MyBackgroundService
{
private readonly IServiceScopeFactory _scopeFactory; // set in ctor
public Task DoStuff()
{
var itens = GetItens();
// Create a scope for the root operation.
using (var scope = _scopeFactory.CreateScope())
{
// Resolve the IConfigurationProvider first to load
// the configuration once eagerly.
var provider = scope.ServiceProvider
.GetRequiredService<IConfigurationProvider>();
var configuration = await provider.GetConfigurationAsync();
Parallel.ForEach(itens, (item) => Process(configuration, item));
}
}
private void Process(Configuration configuration, Item item)
{
// Create a new scope per thread
using (var scope = _scopeFactory.CreateScope())
{
// Request the configuration implementation that allows
// setting the configuration.
var provider = scope.ServiceProvider
.GetRequiredService<DatabaseConfigurationProvider>();
// Set the configuration object for the duration of the scope
provider.Configuration = configuration;
// Resolve an object graph that depends on IConfigurationProvider.
var service = scope.ServiceProvider.GetRequiredService<ItemService>();
service.Process(item);
}
}
}
To pull this off, you need the following DI configuration:
services.AddScoped<DatabaseConfigurationProvider>();
services.AddScoped<IConfigurationProvider>(
p => p.GetRequiredService<DatabaseConfigurationProvider>());
This previous configuration registers DatabaseConfigurationProvider twice: once for its concrete type, once for its interface. The interface registration forwards the call and resolves the concrete type directly. This is a special 'trick' you have to apply when working with the MS.DI container, to prevent getting two separate DatabaseConfigurationProvider instances inside a single scope. That would completely defeat the correctness of this implementation.
Make an interface that extends IDependency and only applies to the faster implementation that you need to request, e.g., IFasterDependency. Then make a registration for IFasterDependency. That way your faster class is still an IDependency object and you won't disrupt too much existing code, but you can now request it freely.
public interface IDependency
{
// Actual, useful interface definition
}
public interface IFasterDependency : IDependency
{
// You don't actually have to define anything here
}
public class SlowClass : IDependency
{
}
// FasterClass is now a IDependencyObject, but has its own interface
// so you can register it in your dependency injection
public class FasterClass : IFasterDependency
{
}
In my Asp.Net Core App I need a singleton service that I can reuse for the lifetime of the application. To construct it, I need a DbContext (from the EF Core), but it is a scoped service and not thread safe.
Therefore I am using the following pattern to construct my singleton service. It looks kinda hacky, therefore I was wondering whether this is an acceptable approach and won't lead to any problems?
services.AddScoped<IPersistedConfigurationDbContext, PersistedConfigurationDbContext>();
services.AddSingleton<IPersistedConfigurationService>(s =>
{
ConfigModel currentConfig;
using (var scope = s.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<IPersistedConfigurationDbContext>();
currentConfig = dbContext.retrieveConfig();
}
return new PersistedConfigurationService(currentConfig);
});
...
public class ConfigModel
{
string configParam { get; set; }
}
What you're doing is not good and can definitely lead to issues. Since this is being done in the service registration, the scoped service is going to be retrieve once when your singleton is first injected. In other words, this code here is only going to run once for the lifetime of the service you're registering, which since it's a singleton, means it's only going to happen once, period. Additionally, the context you're injecting here only exists within the scope you've created, which goes away as soon as the using statement closes. As such, by the time you actually try to use the context in your singleton, it will have been disposed, and you'll get an ObjectDisposedException.
If you need to use a scoped service inside a singleton, then you need to inject IServiceProvider into the singleton. Then, you need to create a scope and pull out your context when you need to use it, and this will need to be done every time you need to use it. For example:
public class PersistedConfigurationService : IPersistedConfigurationService
{
private readonly IServiceProvider _serviceProvider;
public PersistedConfigurationService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task Foo()
{
using (var scope = _serviceProvider.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<IPersistedConfigurationDbContext>();
// do something with context
}
}
}
Just to emphasize, again, you will need to do this in each method that needs to utilize the scoped service (your context). You cannot persist this to an ivar or something. If you're put off by the code, you should be, as this is an antipattern. If you must get a scoped service in a singleton, you have no choice, but more often than not, this is a sign of bad design. If a service needs to use scoped services, it should almost invariably be scoped itself, not singleton. There's only a few cases where you truly need a singleton lifetime, and those mostly revolve around dealing with semaphores or other state that needs to be persisted throughout the life of the application. Unless there's a very good reason to make your service a singleton, you should opt for scoped in all cases; scoped should be the default lifetime unless you have a reason to do otherwise.
Although Dependency injection: Service lifetimes documentation in ASP.NET Core says:
It's dangerous to resolve a scoped service from a singleton. It may cause the service to have incorrect state when processing subsequent requests.
But in your case this is not the issue. Actually you are not resolving the scoped service from singleton. Its just getting an instance of scoped service from singleton whenever it requires. So your code should work properly without any disposed context error!
But another potential solution can be using IHostedService. Here is the details about it:
Consuming a scoped service in a background task (IHostedService)
Looking at the name of this service - I think what you need is a custom configuration provider that loads configuration from database at startup (once only). Why don't you do something like following instead? It is a better design, more of a framework compliant approach and also something that you can build as a shared library that other people can also benefit from (or you can benefit from in multiple projects).
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureAppConfiguration((context, config) =>
{
var builtConfig = config.Build();
var persistentConfigBuilder = new ConfigurationBuilder();
var connectionString = builtConfig["ConnectionString"];
persistentStorageBuilder.AddPersistentConfig(connectionString);
var persistentConfig = persistentConfigBuilder.Build();
config.AddConfiguration(persistentConfig);
});
}
Here - AddPersistentConfig is an extension method built as a library that looks like this.
public static class ConfigurationBuilderExtensions
{
public static IConfigurationBuilder AddPersistentConfig(this IConfigurationBuilder configurationBuilder, string connectionString)
{
return configurationBuilder.Add(new PersistentConfigurationSource(connectionString));
}
}
class PersistentConfigurationSource : IConfigurationSource
{
public string ConnectionString { get; set; }
public PersistentConfigurationSource(string connectionString)
{
ConnectionString = connectionString;
}
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new PersistentConfigurationProvider(new DbContext(ConnectionString));
}
}
class PersistentConfigurationProvider : ConfigurationProvider
{
private readonly DbContext _context;
public PersistentConfigurationProvider(DbContext context)
{
_context = context;
}
public override void Load()
{
// Using _dbContext
// Load Configuration as valuesFromDb
// Set Data
// Data = valuesFromDb.ToDictionary<string, string>...
}
}
I have a text box and a button in my Windows forms application. When the start key is pressed with the value written in the textbox, a new Form should be opened with this value. I want to create a scope for each opened form. And when I close the form I want to close the relevant scope.
How do I create a custom scope with the simple injector?
Here is a simple sample code
static class Program
{
static readonly Container container;
static Program()
{
container = new Container();
container.Register<MyProgram>();
//??
container.Register<MyCustomClass>(Lifestyle.Scoped);
container.Verify();
}
static void Main()
{
//Something...
}
}
class User
{
public int UserID { get; set; }
public string UserName { get; set; }
}
class MyCustomClass
{
User _user;
public MyCustomClass(User user)
{
_user = user;
}
public void Print()
{
Console.WriteLine(_user.UserName);
}
}
class MyProgram
{
public void StartNewScope(string username, int userid)
{
//Start a new scope for this user
}
//End parameter can be different...
public void EndScope(string username)
{
//End relevant scpoe
}
}
The default scoping mechanism in Simple Injector is ambient. This means that you can create a scope, and anywhere within the context of that scope, you can resolve instances. This works great when you have a request of some sort, and within that particular 'bubble', there is only on scope required.
This model, however, is less intuitive when working with Win Forms, when you want to let each Form with its dependencies live in its own scope, since a Form does not live in an isolated context, such as thread or asynchronous context. In that case ambient scoping does not work.
A possible solution to this problem is given in this great answer. The prescribed solution is to register forms as transient and prevent having any scoped dependencies as part of the Form's object graph. Instead, you ensure that a scope is started when a button is pressed, which will end when the button event ends. This can be done, as the answer describes, using some infrastructural code that's part of your Composition Root.
I can highly advise that solution, because it brings an interesting architectural style to the table that is based around the SOLID principles, and as advantage, solves many maintainability issues typical applications have.
If that, however, is not an option, it is possible to switch to ambient-less scoping in Simple Injector.
This requires three things:
Using the ScopedLifestyle.Flowing lifestyle
Manually creating Scope instances
Resolving directly from a Scope instance
The following code shows this in action:
var container = new Container();
// Uses the non-ambient scoped lifestyle
container.Options.DefaultScopedLifestyle = ScopedLifestyle.Flowing;
container.Register<MyCustomClass>(Lifestyle.Scoped);
container.Register<MyForm>();
container.Verify();
using (var scope = new Scope(container))
{
var form = scope.GetInstance<MyForm>();
form.ShowDialog();
}
Sometimes the lifetime of a Form isn't that clear, which will happens when you call Form.Show() instead of Form.ShowDialog. In that case you can tie the lifetime of the scope to that of the Form by hooking onto the Closed event. When .NET closes and disposes the form, so will the Scope with all its Scoped dependencies.
You can do this as follows:
var scope = new Scope(container);
var form = scope.GetInstance<MyForm>();
from.Closed += (s, e) => scope.Dispose();
I would like to implement an application-wide container and a (nested) one for each project created by the user. I looked into Owned<T>, but then - as far as I could figure it out - my internal collection of projects would have to be <Owned<Project>> which I do not want and also I failed to inject a project dependency into objects used within the project scope ("circular component dependency"). I considered using a new ContainerBuilder within the project factory, but then the "nested" aspect is missing.
A few exapmles of classes (with the dependencies) I would like to have:
In a global scope: ProjectManager(IProjectFactory)
In each project's scope: Project(IDocumentFactory documentFactory), Document(IProject project, IProjectSettings settings).
So for the project's scope I would register IDocumentFactory, IProjectSettings (and the project itself?).
When a project is closed/disposed all created dependencies should, of course, also be disposed.
If possible, the concrete classes (except for the ProjectFactory) should be Autofac-agnostic.
FYI: The application is a desktop application using C# and Autofac 4.8.
Thanks!
UPDATE: Thanks for your comments, the discussion helped me find my own opinion. Currently I'm settling for something like this in my ProjectFactory:
public Project Create()
{
var scope = _globalScope.BeginLifetimeScope(MyIocHelper.RegisterProjectDependencies);
var p = scope.Resolve<Project>();
_projectScopes.Add(p, scope);
p.Disposing += project_Disposing;
return p;
}
Things to note:
As far as I can tell, using a tag for the lifetime scope is not necessary.
Project raises a Disposing event when its Dispose method is called the first time.
The factory keeps a Dictionary<Project, ILifetimeScope> and cleans it up when the project is disposed.
You can accomplish what you are looking for with a combination of named lifetime scopes and instance-per-lifetime-scope registrations.
Documentation here: http://autofac.readthedocs.io/en/latest/lifetime/working-with-scopes.html#tagging-a-lifetime-scope
You need to:
register your ProjectManager as SingleInstance
register Project as this:
builder.Register<Project>()
.As<IProject>()
.InstancePerMatchingLifetimeScope("project");
This will guarantee that a Project can be resolved (e.g. by a Document) once per each scope tagged as "project".
Implement an OpenProject (or something along) method in ProjectManager. This method should instantiate a LifetimeScope tagged as "project", register in it the IDocumentFactory, IProjectSettings, so they are resolved only once for each project scope, and attach the scope itself onto the Project instance. This is crucial: you need the scope to be disposed when you dispose the project.
public class ProjectManager : IProjectFactory
{
private readonly ILifetimeScope _scope;
public ProjectManager(ILifetimeScope scope)
{
// this is going to be the global scope.
_scope = scope;
}
public Project OpenProject(IDocumentFactory docFactory, IProjectSettings settings)
{
var projectScope = _scope.BeginLifetimeScope("project");
projectScope.RegisterInstance(docFactory).AsImplementedInterfaces();
projectScope.RegisterInstance(settings).AsImplementedInterfaces();
return projectScope.Resolve<Project>();
}
}
public class ProjectScope : IDisposable
{
private readonly ILifetimeScope _scope;
public ProjectManager(ILifetimeScope scope)
{
// this is going to be the project scope.
_scope = scope;
}
public void Dispose() {
if (_scope != null) {
_scope.Dispose();
_scope = null;
}
}
}
public class Project : IDisposable
{
private readonly ProjectScope _scope;
public Project(ProjectScope scope /*, ...*/)
{
_scope = scope;
}
public void Dispose() {
// pay attention that this method will be called 2 times, once by you
// and another time by the underlying LifetimeScope. So this code should
// handle that gracefully (so the _scope == null).
if (_scope != null) {
_scope.Dispose();
_scope = null;
}
}
}
Given all this, you keep every using Autofac out of every class, with the 2 exceptions of the global manager and the ProjectScope. You can change some bits on how the scope is handled, if you accept a single using Autofac in the Project class itself: you can get directly the ILifetimeScope and dispose of it directly.
Hope this helps!
I could well be misunderstanding something here, so perhaps there is a simple answer here but I'm currently scratching my head.
I have a class UnitOfWork that implements IUnitOfWork (yes yes I know). The constructor for unit of work takes an IPrincipalFactory. TResponder is the top level of the graph which takes an IUnitOfWork.
I'm trying to register the ApplicationPrincipalFactory as a specific instance in a lifetime scope... it's dependant on some properties passed to the HandleAsync function. I'm doing the following:
public async Task<TResponse> HandleAsync<TMessage, TResponse, TResponder>(TMessage message)
where TMessage : class
where TResponder : IRespondAsync<TMessage, TResponse>
{
using (var scope = this.BeginLifetimeScope(message))
{
var responder = scope.Resolve<TResponder>();
return await responder.Respond(message);
}
}
private ILifetimeScope BeginLifetimeScope<TMessage>(TMessage message)
{
var unwrapped = GetDomainContext(message);
var applicationPrincipalFactory = this.CreateApplicationPrincipalFactory(unwrapped);
var lifetime = this.container.BeginLifetimeScope(
r => r.RegisterInstance(applicationPrincipalFactory).As<IPrincipalFactory>());
return lifetime;
}
private ApplicationPrincipalFactory CreateApplicationPrincipalFactory(IDomainContext unwrapped)
{
var applicationPrincipalFactory =
new ApplicationPrincipalFactory(
unwrapped.Tenant,
unwrapped.ActingTenant,
unwrapped.Username);
return applicationPrincipalFactory;
}
Based on everything I've read, defining the dependency within BeginLifetimeScope(r => should override the parent container binding, so when I call resolve, it should all slot neatly together.
However, I get an exception:
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Platform.Engine.Persistence.UnitOfWork' can be invoked with the available services and parameters: Cannot resolve parameter 'Platform.Engine.Security.IPrincipalFactory principalFactory' of constructor
I am not registering the IPrincipalFactory anywhere other than in this method. The IUnitOfWork is defined in the outer scope as follows:
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
I have also tried re-defining the unitofwork registration within the child container in case it was an issue cause by registering it in the outer container rather than the lifetime one:
var lifetime = this.container.BeginLifetimeScope(
r => r.RegisterInstance(applicationPrincipalFactory).As<IPrincipalFactory>());
var overrides = new ContainerBuilder();
overrides.RegisterType<UnitOfWork>().As<IUnitOfWork>();
overrides.Update(lifetime.ComponentRegistry);
return lifetime;
I'm not sure what I'm missing... any ideas or suggestions?
Register your factory with the rest of your types during the initial container configuration.
builder.RegisterType<ApplicationPrincipalFactory>().As<IPrincipalFactory>();
Then in your lifetime scope resolve a delegate factory that you can pass the context into.
var factory = container.Resolve<Func<IDomainContext, IPrincipalFactory>>();
var instance = factory(context);
You could also add three string parameters to the Func<> signature, but since you already have a nice context object I would just pass that in instead.
Finally, use the factory as needed.
instance.DoesSomethingButNotSureWhat();
That will prevent you from having to update the lifetime scope just to pass in the context parameter.