How to clean up instances created by SimpleInjector during verification? - c#

As a part of creating my SimpleInjector container, I've followed recommended practices and called container.Verify() to check that my type registrations make sense.
This works well and has caught a number of errors that I've made - but it also creates debris that lingers around afterwards that I'd like to clean up.
One of my classes is a singleton event hub that's used to route messages between other transient components; these other components accept the event hub in their constructor, create a subscription to receive the messages they're interested in receiving, then Dispose() the subscription when they're finished.
The call to container.Verify() creates one of each kind of object, resulting in a number of these otherwise transient instances lingering around because the event hub still knows about their subscriptions.
At the moment I've worked around the problem by manually terminating all subscriptions immediately after the Verify() call, before the application starts up. However, this feels like a problem that must be already solved, though I haven't been able to find an answer in the docs, here on Stack Overflow, or by searching.
Perhaps using a scoped lifestyle is the solution? They didn't seem relevant because I'm building a WPF application, but if I knew the answer I wouldn't be asking here!
Update, 12 Jan - As requested by #steven, here's some code to demonstrate my issue.
I tried (and failed) to demonstrate the issue with something that was both compilable and short enough to share inline; instead I'm showing some code excerpts from the actual project. If you want to see the whole thing, the WordTutor project is on GitHub.
At the core of my application I have a singleton IReduxStore<T> which both encapsulates application state and acts as a kind of event hub. Other classes subscribe to the store in order to be proactively notified when the application state changes.
Here is IReduxStore<T>, pared down to the essentials:
// IReduxStore.cs
public interface IReduxStore<T>
{
T State { get; }
void Dispatch(IReduxMessage message);
IDisposable SubscribeToReference<V>(
Func<T, V?> referenceReader,
Action<V?> whenChanged)
where V : class, IEquatable<V>?;
}
Subscriptions implement IDisposable as a convenient and idiomatic way for deterministic cleanup when the subscription is no longer required.
The store is registered as a singleton, bound to a specific type of state:
// Program.cs
container.RegisterSingleton<
IReduxStore<WordTutorApplication>,
ReduxStore<WordTutorApplication>>();
The implementation of IReduxStore<T> stores all the subscriptions:
private readonly HashSet<ReduxSubscription<T>> _subscriptions
= new HashSet<ReduxSubscription<T>>();
They're removed from the HashSet when disposed.
Many of my ViewModels accept IReduxStore<WordTutorApplication> to their constructors so they can subscribe to updates:
// VocabularyBrowserViewModel.cs
public sealed class VocabularyBrowserViewModel : ViewModelBase
{
private readonly IReduxStore<WordTutorApplication> _store;
private readonly IDisposable _screenSubscription;
private readonly IDisposable _vocabularySubscription;
public VocabularyBrowserViewModel(IReduxStore<WordTutorApplication> store)
{
_store = store ?? throw new ArgumentNullException(nameof(store));
// ... elided ...
_screenSubscription = _store.SubscribeToReference(
app => app.CurrentScreen as VocabularyBrowserScreen,
RefreshFromScreen);
_vocabularySubscription = _store.SubscribeToReference(
app => app.VocabularySet,
RefreshFromVocabularySet);
// ... elided ...
}
// ... elided ...
}
ViewModels are registered as transient because each window needs a unique instance:
// Program.cs
var desktopAssembly = typeof(WordTutorWindow).Assembly;
container.Collection.Register<ViewModelBase>(desktopAssembly);
The ViewModels release their subscriptions proactively when they are no longer needed:
// VocabularyBrowserViewModel.cs
private void RefreshFromScreen(VocabularyBrowserScreen? screen)
{
if (screen == null)
{
_screenSubscription.Dispose();
_vocabularySubscription.Dispose();
return;
}
Selection = screen.Selection;
Modified = screen.Modified;
}
When Verify() is called on the SimpleInjector container, an exemplar of every object is created, including the singleton IReduxStore<T>. The transient viewmodels (such as VocabularyBrowserViewModel shown above) are also created, but those instances remain live because their subscriptions are still held by the store.
I tried implementing IDisposable on the ViewModels, but because their lifestyle is transient, the only effect was to generate an additional warning when Verify() was called.
Update II, 12 Jan:
The workaround I have at the moment is to manually clear all the subscriptions as a part of application startup, after the container has been successfully initialized:
var store = (ReduxStore<WordTutorApplication>)
container.GetInstance<IReduxStore<WordTutorApplication>>();
store.ClearSubscriptions();
This feels like a nasty hack. First it needs to explicitly cast to the implementation type, then it calls a method that otherwise wouldn't need to exist at all.

Try setting EnableAutoVerification to false in Simple Injector 5.0 (https://simpleinjector.org/ReferenceLibrary/html/P_SimpleInjector_ContainerOptions_EnableAutoVerification.htm)

Related

How to correctly and safely dispose of singletons instances registered in the container when an ASP.NET Core app shuts down

I am looking for guidance on how to correctly and safely dispose of registered singleton instances when my ASP.NET Core 2.0 app is shutting down.
According to the following document, if I register a singleton instance (via IServiceCollection) the container will never attempt to create an instance (nor will it dispose of the instance), thus I am left to dispose of these instances myself when the app shuts down.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.0 (2.1 has the same guidance)
I enclose some pseudo code that illustrates what I am trying to achieve.
Note I am having to maintain a reference to IServiceCollection since the IServiceProvider provided to the OnShutDown method is a simple service locator and doesn't give me the ability to execute complex queries.
When the app shuts down I want a generic way to ensure all singleton instances are disposed. I could maintain a reference to all these singleton instances directly but this doesn't scale well.
I originally used the factory method which would ensure the DI managed the lifetime of my objects, however, the execution of the factory method happened at runtime in the pipeline of handling a request, which meant that if it threw an exception the response was 500 InternalServerError and an error was logged. By creating the object directly I am striving for faster feedback so that errors on startup lead to a automatic rollback during the deployment. This doesn't seem unreasonable to me, but then at the same time I don't to misuse the DI.
Does anyone have any suggestions how I can achieve this more elegantly?
namespace MyApp
{
public class Program
{
private static readonly CancellationTokenSource cts = new CancellationTokenSource();
protected Program()
{
}
public static int Main(string[] args)
{
Console.CancelKeyPress += OnExit;
return RunHost(configuration).GetAwaiter().GetResult();
}
protected static void OnExit(object sender, ConsoleCancelEventArgs args)
{
cts.Cancel();
}
static async Task<int> RunHost()
{
await new WebHostBuilder()
.UseStartup<Startup>()
.Build()
.RunAsync(cts.Token);
}
}
public class Startup
{
public Startup()
{
}
public void ConfigureServices(IServiceCollection services)
{
// This has been massively simplified, the actual objects I construct on the commercial app I work on are
// lot more complicated to construct and span several lines of code.
services.AddSingleton<IDisposableSingletonInstance>(new DisposableSingletonInstance());
// See the OnShutdown method below
this.serviceCollection = services;
}
public void Configure(IApplicationBuilder app)
{
var applicationLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
applicationLifetime.ApplicationStopping.Register(this.OnShutdown, app.ApplicationServices);
app.UseAuthentication();
app.UseMvc();
}
private void OnShutdown(object state)
{
var serviceProvider = (IServiceProvider)state;
var disposables = this.serviceCollection
.Where(s => s.Lifetime == ServiceLifetime.Singleton &&
s.ImplementationInstance != null &&
s.ServiceType.GetInterfaces().Contains(typeof(IDisposable)))
.Select(s => s.ImplementationInstance as IDisposable).ToList();
foreach (var disposable in disposables)
{
disposable?.Dispose();
}
}
}
}
It's the DI's job to dispose of any IDisposable objects it creates, whether transient, scoped or singleton. Don't register existing singletons unless you intend to clean them up afterwards.
In the question's code there's no reason to register an instance of DisposableSingletonInstance. It should be registered with :
services.AddSingleton<IDisposableSingletonInstance,DisposableSingletonInstance>();
When the IServiceCollection gets disposed, it will call Dispose() on all the disposable entities created by it. For web applications, that happens when RunAsync() ends;
The same holds for scoped services. In this case though, the instances will be disposed when the scope exits, eg when a request ends.
ASP.NET creates a scope for each request. If you want your service to be disposed when that request ends, you should register it with :
services.AddScoped<IDisposableSingletonInstance,DisposableSingletonInstance>();
Validation
For the latest edit :
By creating the object directly I am striving for faster feedback so that errors on startup lead to a automatic rollback during the deployment.
That's a different problem. Deployment errors are often caused by bad configuration values, unresponsive databases etc.
Validating Services
A very quick & dirty way to check would be to instantiate the singleton once all startup steps are complete with :
services.GetRequiredService<IDisposableSingletonInstance>();
Validating Configuration
Validating the configuration is more involved but not that tricky. One could use Data Annotation attributes on the configuration classes for simple rules and use the Validator class to validate them.
Another option is to create an IValidateable interface with a Validate method that has to be implemented by each configuration class. This makes discovery easy using reflection.
This article shows how the IValidator interface can be used in conjunction with an IStartupFilter to validate all configuration objects when an application starts for the first time
From the article :
public class SettingValidationStartupFilter : IStartupFilter
{
readonly IEnumerable<IValidatable> _validatableObjects;
public SettingValidationStartupFilter(IEnumerable<IValidatable> validatableObjects)
{
_validatableObjects = validatableObjects;
}
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
foreach (var validatableObject in _validatableObjects)
{
validatableObject.Validate();
}
//don't alter the configuration
return next;
}
}
The constructor gets all instances that implement IValidatable from the DI provider and calls Validate() on them
That's not accurate. Singletons are disposed at app shutdown, though it's kind of not actually all that relevant because when the process stops, everything goes with it anyways.
The general rule of thumb is that when using DI, you should use DI all the way down, which then means you'll almost never be disposing on your own, anywhere. It's all about ownership. When you new stuff up yourself, you're also then responsible for disposing of it. However, when using DI, the container is what's newing things up, and therefore, the container and only the container should then dispose of those things.
Thanks for the responses Panagiotis Kanavos and Chris Pratt and for helping to clarify how best to deal with this scenario. The two take away points are this:
Always strive to let the container manage the life cycle of your objects so when the app is shutdown the container will automatically dispose of all objects.
Validate all your configuration on app startup before it is consumed by objects registered in the container. This allows your app to fail fast and protects your DI from throwing exceptions when creating new objects.

Use of ResolveUnregisteredType causes Torn Lifestyle warning in Simple Injector v3.0.3

I use a self-made "external" library to get some basic infrastructure in place when creating new web-applications. I recently made some changes to how my repositories work and came across this warning from Simple Injector Diagnostic Warnings:
SimpleInjector.DiagnosticVerificationException : The configuration is
invalid. The following diagnostic warnings were reported:
-[Torn Lifestyle] The registration for IUnitOfWork maps to the same implementation and lifestyle as the registrations for IUnitOfWork,
IUnitOfWork, IUnitOfWork and IUnitOfWork do. They all map to
EmptyUnitOfWork (Singleton). This will cause each registration to
resolve to a different instance: each registration will have its own
instance. See the Error property for detailed information about the
warnings. Please see https://simpleinjector.org/diagnostics how to fix
problems and how to suppress individual warnings.
The core assembly of my library has an empty implementation of IUnitOfWork called EmptyUnitOfWork which is just a simple no-op class:
internal sealed class EmptyUnitOfWork : IUnitOfWork
{
public void SaveChanges()
{
// Do nothing
}
}
This class is then registered in the container when there is no other unit of work avaliable. I do this by using the container.ResolveUnregisteredType(...) like so:
// Register an EmptyUnitOfWork to be returned when a IUnitOfWork is requested:
container.ResolveUnregisteredType += (sender, e) =>
{
if (e.UnregisteredServiceType == typeof(IUnitOfWork))
{
// Register the instance as singleton.
var registration = Lifestyle.Singleton.CreateRegistration<IUnitOfWork, EmptyUnitOfWork>(container);
e.Register(registration);
}
};
First time I've used above method - but works fine with this test:
[Fact]
public void RegistersEmptyUnitOfWork_AsSingleton_WhenIUnitOfWorkIsNotRegisted()
{
var instance = _container.GetInstance<IUnitOfWork>();
var registration = _container.GetRegistration(typeof (IUnitOfWork));
Assert.NotNull(instance);
Assert.IsType<EmptyUnitOfWork>(instance);
Assert.Equal(Lifestyle.Singleton, registration.Lifestyle);
}
Now for the fun part, I have an extension method in a supporting library which registers an EntityFramework IUnitOfWork if my application needs one:
public static void RegisterEntityFramework<TContext>(this Container container) where TContext : DbContext
{
if (container == null)
throw new ArgumentNullException(nameof(container));
var lifestyle = Lifestyle.CreateHybrid(() =>
HttpContext.Current != null,
new WebRequestLifestyle(),
new LifetimeScopeLifestyle()
);
container.Register<DbContext, TContext>(lifestyle);
container.Register<IUnitOfWork, EntityFrameworkUnitOfWork>(lifestyle);
container.Register(typeof (IRepository<>), typeof (EntityFrameworkRepository<>), lifestyle);
}
But somehow this throws the warning from Simple Injector - but I just injected the EntityFrameworkUnitOfWork so the EmptyUnitOfWork should not be triggered?
The reason for this design is that I have a CommandTransactionDecorator in my core library which uses the IUnitOfWork to save changes. I just want to have an empty one if a IUnitOfWork is not required by the application.
For reference this is the decorator:
internal sealed class CommandTransactionDecorator<TCommand> : IHandleCommand<TCommand> where TCommand : ICommand
{
private readonly IUnitOfWork _unitOfWork;
private readonly Func<IHandleCommand<TCommand>> _handlerFactory;
public CommandTransactionDecorator(IUnitOfWork unitOfWork, Func<IHandleCommand<TCommand>> handlerFactory)
{
_unitOfWork = unitOfWork;
_handlerFactory = handlerFactory;
}
public void Handle(TCommand command)
{
_handlerFactory().Handle(command);
_unitOfWork.SaveChanges();
}
}
UPDATE
It seems like this is the registration that makes the warning:
var registration = Lifestyle.Singleton.CreateRegistration<IUnitOfWork, EmptyUnitOfWork>(container);
e.Register(registration);
Changing it to e.Register(() => new EmptyUnitOfWork()); makes the warning go away, but then the lifestyle is not singleton?
What you are seeing is that ResolveUnregisteredType is called multiple times. This causes multiple singleton registrations for the same type to be made. Each registration gets its own instance. This will result in an application that consists of multiple instances of that type, which is usually not what you want to happen when you register a type as singleton. Since your EmptyUnitOfWork doesn't have any behavior, there is probably no problem, but Simple Injector can obviously not guess that this is the case, so it throws an exception.
What you are experiencing however is a breaking change / bug that was introduced in Simple Injector v3. In Simple Injector v1 and v2 the resulting registration of a ResolveUnregisteredType was cached; which meant that a call to Verify() would trigger your custom delegate just once. In Simple Injector v3.0 however, the resulting registration isn't cached anymore. This was an oversight, that has slipped through. The idea was to make ResolveUnregisteredType context aware. To be context aware, caching was not an option anymore. So caching was removed, but we eventually decided not to make ResolveUnregisteredType context aware, while we forgot to add the caching again.
The funny thing of this accidental behavior however is, that it expose a bug in your code. This bug already existed even when you used v2, but v3 now (accidentally) slaps you in the face with it. With v2, the correctness of your registration depended on the use of the Verify() method. Verify() builds all object graphs on a single thread. Without the use of Verify() however, the object graphs are compiled lazily and in case you are running a multi-threaded application, multiple threads can simultaneously call ResolveUnregisteredType; Simple Injector never locked ResolveUnregisteredType and this is documented.
So the result of this is that without a call to Verify() you could still end up in multiple registrations of that specific component, which of course again could lead to really ugly hard to find problems, that usually only appear once in a way in production.
This is how you should actually write that registration:
Lazy<Registration> registration = new Lazy<Registration>(() =>
Lifestyle.Singleton.CreateRegistration<IUnitOfWork, EmptyUnitOfWork>(container));
container.ResolveUnregisteredType += (sender, e) => {
if (e.UnregisteredServiceType == typeof(IUnitOfWork)) {
e.Register(registration.Value);
}
};
With Simple Injector v3 however, you hardly ever have to use the ResolveUnregisteredType event anymore. You can do make the following registration instead:
container.RegisterConditional<IUnitOfWork, EntityFrameworkUnitOfWork>(Lifestyle.Scoped,
c => true);
// NOTE: This registration must be made second
container.RegisterConditional<IUnitOfWork, EmptyUnitOfWork>(Lifestyle.Singleton,
c => !c.Handled);
This solves the problem of having to think about multi-threading completely. Here we make two conditional registrations, where the first is always applied (using the predicate c => true). You might be tempted to make the first registration unconditional using Register<IUnitOfWork, EFUoW>(), but that won't work, because Simple Injector will detect that the second registration can never be applied and an exception will be thrown. So the use of the c => true predicate suppresses this detection. I wouldn't usually advice such construct, because it blinds Simple Injector. In your case however it seems reasonable, because both registrations are made at different moment.
I now will have to think about whether or not I want to change this behavior in v3 and do caching. Advantage of caching is that it can improve performance, but the downside is that it hides bugs.

Simple Injector FilterInjection seems to be reinitialising RegisterPerWebRequest injected item

I'm trying to move from Ninject to Simple Injector but I'm experiencing an odd issue when trying to duplicate functionality that worked with Ninject.
In Ninject I had a service which contained:
private readonly ICollection<Message> messages;
This service was registered as
Bind<INotificationService>().To<NotificationService>()
.InRequestScope();
This service allowed messages (UI and error) to be passed back to the MVC site.
This service was injected into an ActionFilterAttribute:
kernel.BindFilter<CriticalErrorAttribute>(FilterScope.Last, 1)
.When((context, ad) =>
!string.IsNullOrEmpty(ad.ActionName) &&
ad.ControllerDescriptor.ControllerName.ToLower() != "navigation");
and used within OnActionExecuted.
Because the service was registered to Ninject with InRequestScope, any items pushed to the message queue were available in the Actionfiter. This allowed for a redirect to an error page (displaying critical errors) if necessary.
I've tried to duplicate this with simpleinjector:
container.RegisterPerWebRequest<INotificationService, NotificationService>();
container.RegisterInitializer<CriticalErrorAttribute>(handler =>
{
handler.NotificationService =
container.GetInstance<INotificationService>();
});
The injection is working fine, but even though the message collection contains messages prior to entering the ActionFilter, once in the filter the message collection is empty. It's like the RegisterPerWebRequest is being ignored.
Any help in solving this issues would be appreciated.
UPDATE:
In Simple Injector 2.5 a new RegisterMvcIntegratedFilterProvider extension method has been added to the MVC Integration package that replaces the old RegisterMvcAttributeFilterProvider. This new RegisterMvcIntegratedFilterProvider contains the behavior of the SimpleInjectorFilterAttributeFilterProvider that is given below and allows better integration of attributes into the Simple Injector pipeline. This does mean however that by default, no properties are injected, but this can extended by implementing a custom IPropertySelectionBehavior. The use of the new RegisterMvcIntegratedFilterProvider is adviced over the old RegisterMvcAttributeFilterProvider method, which will be marked [Obsolete] in a future release.
When using the RegisterMvcAttributeFilterProvider extension method, Simple Injector will not call any registered initializer on MVC attributes. If you set a break point inside the anonymous delegate that injects the NotificationService you'll see it's never hit.
Simple Injector does however call the container.InjectProperties method on MVC attributes, but InjectProperties does implicit property injection, which means that it tries to inject all public properties on a type, but skips it if the property can't be injected (for what ever reason).
I bet the CriticalErrorAttribute.NotificationService property has a type of NotificationService instead of INotificationService. Since you didn't register NotificationService explicitly, the container will create a transient instance for you, which means you'll get a different instance for the CriticalErrorAttribute than the rest of the application is getting.
Quick fix: change the property type to INotificationService.
To be honest, I regret ever implemented the MVC integration package for Simple Injector to use the InjectProperties method. Implicit Property injection is very evil, because it doesn't fail fast when there's a misconfiguration and I'm even thinking about removing support for InjectProperties in the future. The problem is however that many developers are depending on InjectProperties. Either directly by calling it, or indirectly by letting the container inject properties on MVC attributes.
InjectProperties does not run any initializer. That's by design, and there are other constructs that allow running the full initialization process on objects that are not created by the container. Problem is however, that adding this could break existing clients, since this could result in properties being injected multiple times.
In your case, I suggest a different solution:
Prevent calling container.RegisterMvcAttributeFilterProvider() in the startup path of your application. This will register a special FilterAttributeFilterProvider that calls InjectProperties internally. You don't want to use implicit property injection, you want a more explicit (and complete) behavior. Instead register the following class:
internal sealed class SimpleInjectorFilterAttributeFilterProvider
: FilterAttributeFilterProvider
{
private readonly ConcurrentDictionary<Type, Registration> registrations =
new ConcurrentDictionary<Type, Registration>();
private readonly Func<Type, Registration> registrationFactory;
public SimpleInjectorFilterAttributeFilterProvider(Container container)
: base(false)
{
this.registrationFactory = type =>
Lifestyle.Transient.CreateRegistration(type, container);
}
public override IEnumerable<Filter> GetFilters(
ControllerContext context,
ActionDescriptor descriptor)
{
var filters = base.GetFilters(context, descriptor).ToArray();
foreach (var filter in filters)
{
object instance = filter.Instance;
var registration = registrations.GetOrAdd(
instance.GetType(), this.registrationFactory);
registration.InitializeInstance(instance);
}
return filters;
}
}
You can use the following code to register this custom provider:
var filterProvider =
new SimpleInjectorFilterAttributeFilterProvider(container);
container.RegisterSingle<IFilterProvider>(filterProvider);
var providers = FilterProviders.Providers
.OfType<FilterAttributeFilterProvider>().ToList();
providers.ForEach(provider => FilterProviders.Providers.Remove(provider));
FilterProviders.Providers.Add(filterProvider);
This custom SimpleInjectorFilterAttributeFilterProvider calls the Registration.InitializeInstance method. This method allows initialization a type that is already created and will initialize it by (among other things) calling the type initializer delegates.
For more information about working with attributes, please read the following discussion.

How do I spawn child thread processes when using shared entities injected via Unity?

I have an ASP.Net MVC3 solution running a batch import process which fetches data from a web-service. For each row/loop, the process needs to send up to four emails. I'd like to fire these emails off in background threads so that the main thread doesn't have to wait for the emails to be sent. The child email thread needs to update the database audit table on email send completion or failure.
The issue I'm having is that I use Unity to inject the IEmailer class into my main process thread, which also assigns the 'main process thread' datacontext into the emailer class. So I get errors when the datacontext has already been closed when the emailer tries to update the audit table if the main loop has already finished (a plausible scenario).
How do I tell Unity to assign a new datacontext to my new emailer threads, or how do I tell my emailer class to use a different unity container (configured with Transient datacontext, I guess?)?
Here's my stripped down code. (I realise I could just instantiate a 'new MyDataContext()' inside the emailer but there is definitely a better way).
Any help, suggestions, ideas or comments will be greatly appreciated - thank you!
IOC Container
this.unityContainer = new UnityContainer()
.RegisterType<IDataProvider, DataProvider>()
.RegisterType(typeof(IEmailer), typeof(Emailer))
.RegisterType<DbContext, MyDataContext>(new HierarchicalLifetimeManager());
Import class (main thread)
public class DataSyncer : IDataSyncer
{
public DataSyncer(IDataProvider dataProvider, IEmailer emailer) {
this.dataProvider = dataProvider;
this.emailer = emailer;
}
public void Import(Guid key) {
// some import code
emailer.EmailAddress = "someone#somewhere.com";
emailer.Subject = "subject line";
new Thread(emailer.SendMail).Start(); // send email in new thread
}
}
Emailer class (for child threads)
public class Emailer : IEmailer
{
[Dependency]
public IDataProvider DataProvider { get; set; }
// etc
}
DataProvider (contains datacontext via ctor injection)
public DataProvider(MyDataContext context, // etc) { // etc }
I'm trying to rephrase your explanation to see if I got it right.
Your importer runs on the main thread. You fire of emails for every row you import. Your emailer needs to write audit information to the database upon success or failure of the process.
The emailer is injected into your importer and both have a dependency on a class derived from DbContext? Is that the same instance of the DbContext? If so: Why do you share that instance? Isn't each task of sending an email independent from all other tasks? If so, remove the HierarchicalLifetimeManager.
You use property injection for your IDataProvider. I understood that this is a must-have dependency. If that is the case you should use constructor injection like you already do for the other classes. By the way: Don't use the DependencyAttribute. You can also configure property injection using InjectionProperty in your call to RegisterType.
Update
As far as I know Unity never cleans up after itself. Meaning I would not expect it to call Dispose on your DbContext anyway. Do you have a reference where it says that the HierarchicalLifetimeManager disposes objects properly? I would be very interested to read it!
HierarchicalLifetimeManager works the same way as ContainerControlledLifetimeManager as long as you don't deal with child containers. That basically means that you have a single instance of your context across all threads. If you just remove that lifetime manager you would get a new instance whenever one is needed as a dependency. That should solve your problem.
If you need to take care of the disposal of your context instances I would inject a factory for the context instead of an instance. Just declare a ctor parameter of Type Func<MyDataContext> Unity will automatically generate the delegate for you (that feature is called automatic factories btw.). Then you can use using(var ctx = dbContextFactory()) { ... }.

Constructor parameters for dependent classes with Unity Framework

I just started using the Unity Application Block to decouple my classes and make unit testing easier. However, I've run into a problem with circular dependencies.
I have a facade-type class which is a chat bot. It is a singleton class which handles all sort of secondary classes and provides a central place to launch and configure the bot. I also have a class called AccessManager which, well, manages access to bot commands and resources. Boiled down to the essence, I have the classes set up like so:
public class Bot
{
public string Owner { get; private set; }
public string WorkingDirectory { get; private set; }
private IAccessManager AccessManager;
private Bot()
{
// do some setup
// LoadConfig sets the Owner & WorkingDirectory variables
LoadConfig();
// init the access mmanager
AccessManager = new MyAccessManager(this);
}
public static Bot Instance()
{
// singleton code
}
...
}
And the AccessManager class:
public class MyAccessManager : IAccessManager
{
private Bot botReference;
public MyAccesManager(Bot botReference)
{
this.botReference = botReference;
SetOwnerAccess(botReference.Owner);
}
private void LoadConfig()
{
string configPath = Path.Combine(
botReference.WorkingDirectory,
"access.config");
// do stuff to read from config file
}
...
}
I would like to change this design to use the Unity Application Block. I'd like to use Unity to generate the Bot singleton and to load the AccessManager interface in some sort of bootstrapping method that runs before anything else does.
public static void BootStrapSystem()
{
IUnityContainer container = new UnityContainer();
// create new bot instance
Bot newBot = Bot.Instance();
// register bot instance
container.RegisterInstance<Bot>(newBot);
// register access manager
container.RegisterType<IAccessManager,MyAccessManager>(newBot);
}
And when I want to get a reference to the Access Manager inside the Bot constructor I can just do:
IAcessManager accessManager = container.Resolve<IAccessManager>();
And elsewhere in the system to get a reference to the Bot singleton:
// do this
Bot botInstance = container.Resolve<Bot>();
// instead of this
Bot botInstance = Bot.Instance();
The problem is the method BootStrapSystem() is going to blow up. When I create a bot instance it's going to try to resolve IAccessManager but won't be able to because I haven't registered the types yet (that's the next line). But I can't move the registration in front of the Bot creation because as part of the registration I need to pass the Bot as a parameter! Circular dependencies!! Gah!!!
This indicates to me I have a flaw in the way I have this structured. But how do I fix it? Help!!
You can make your life easier by changing the design in the following ways:
Don't implement the Singleton pattern yourself. The DI Container should manage the lifetime of all components, including the Bot class. If you only want a single instance in your application, configure Unity to always return the same instance.
Do everything in your power to remove circular dependencies. You can often do that by changing one of the communication directions to use events instead of direct calls. Another option is to introduce a Mediator.
Notice that none of these recommendations particularly involve Unity. Unity (or any other DI Container) is not a silver bullet that will magically make your code loosely coupled. You must first understand the principles behind DI, and then you can use any DI Container as a tool to help you wire up the dependency graph.
First of all you should let the container manage your singleton lifetime instead of writing the singleton code yourself. To remove your circular dependency, you can remove the Bot from the access manager constructor. Instead, you use an initialize method.
container.RegisterType<Bot>(new ContainerControlledLifecycleManager()); // from my memory...
container.RegisterType<IAccessManager,MyAccessManager>();
var bot = container.Resolve<Bot>();
// Bot.cs
public Bot(IAccessManager manager)
{
manager.InitializeFor(this);
}
For testability reasons you should never call your IOC container from a constructor.

Categories

Resources