This question is more of a "how do I do it?", rather than a "what am I doing wrong?". I have a class which is called QueryProcessor that processes queries (think CQRS). That object is injected into my presenters. The QueryProcessor needs to use the kernel to resolve bindings. Injecting the kernel in, either directly or via a factory, is easy. Doing so without causing a memory leak is the trick.
I have verified using a memory profiler that none of my QueryProcessor objects are being garbage collected. The class looks like this:
public sealed class QueryProcessor : IQueryProcessor, IDisposable
{
private readonly IKernelFactory _container;
private bool _disposed;
public QueryProcessor(IKernelFactory container)
{
_container = container;
}
//[DebuggerStepThrough]
public TResult Process<TResult>(IQuery<TResult> query)
{
var handlerType = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResult));
dynamic handler = _container.RetrieveKernel().Get(handlerType);
return handler.Handle((dynamic)query);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing && !_disposed)
{
// dispose of stuff here
_disposed = true;
}
}
}
public interface IKernelFactory
{
IKernel RetrieveKernel();
}
My composition root is reasonably straightforward. I am using the factory extension of Ninject.
public void OnLoad(IKernel kernel)
{
// Auto-Register all the validators which are stored in the Service assembly.
AssemblyScanner.FindValidatorsInAssembly(_serviceAssembly).ForEach(
result => kernel.Bind(result.InterfaceType, result.ValidatorType)
);
ManualRegistrations(kernel);
kernel.Bind<IKernelFactory>().ToFactory();
AutoRegisterType(kernel, typeof(IQueryHandler<,>));
AutoRegisterType(kernel, typeof(ICommandHandler<>));
}
As mentioned, the injection is working, but it is leaving a memory leak. How am I supposed to get the Ninject kernel resolving stuff in my QueryProcessor without causing the leak?
Thanks
Update - New Problem
I tried to solve this problem by creating a new kernel with a new module, separate from the main kernel of the Composition Root. These sub-kernels would be created and disposed up, with their lifetimes being tied to that of the QueryProcessors. I hooked it up like this in the main module:
kernel.Bind<IQueryProcessor>().ToMethod(ctx => new QueryProcessor(new StandardKernel(new ProcessorModule(_serviceAssembly)))).InTransientScope();
It works fine before the kernel is disposed of for the first time. But after that, I get the following error message:
Error loading Ninject component ICache
No such component has been registered in the kernel's component container.
Suggestions:
1) If you have created a custom subclass for KernelBase, ensure that you have properly
implemented the AddComponents() method.
2) Ensure that you have not removed the component from the container via a call to RemoveAll().
3) Ensure you have not accidentally created more than one kernel.
Damned if I do, damned if I don't ...
Since your application, not the DI container, is creating the instance it is also responsible for disposing the instance. This scenario can be handled by using the Register, Resolve, and Release pattern.
If you inject the kernel, then you have effectively implemented the service locator anti-pattern. This means your application is explicitly dependent on your DI framework.
Rather than injecting the kernel, you should use an abstract factory as mentioned in the post DI Friendly Framework to handle both creating and releasing the handler instances.
public interface IHandlerFactory
{
dynamic Create(Type handlerType);
void Release(dynamic handler);
}
public interface HandlerFactory
{
private readonly Func<Type, dynamic> handlerMethod;
public HandlerFactory(Func<Type, dynamic> handlerMethod)
{
if (handlerMethod == null)
throw new ArgumentNullException("handlerMethod");
this.handlerMethod = handlerMethod;
}
public dynamic Create(Type handlerType)
{
return handlerMethod(handlerType);
}
public void Release(dynamic handler)
{
IDisposable disposable = handler as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}
Usage
public sealed class QueryProcessor : IQueryProcessor
{
private readonly IHandlerFactory handlerFactory;
public QueryProcessor(IHandlerFactory handlerFactory)
{
if (handlerFactory == null)
throw new ArgumentNullException("handlerFactory");
this.handlerFactory = handlerFactory;
}
//[DebuggerStepThrough]
public TResult Process<TResult>(IQuery<TResult> query)
{
var handlerType = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResult));
dynamic handler = this.handlerFactory.Create(handlerType);
try
{
return handler.Handle((dynamic)query);
}
finally
{
this.handlerFactory.Release(handler);
}
}
}
Note that if you use this approach, you are not requiring every handler to implement IDisposable, nor does your QueryProcessor unnecessarily need to implement IDisposable.
In your composition root, you just need to implement the handler method and register it as a parameter to your factory.
Func<Type, dynamic> handlerMethod = type => (dynamic)kernel.Resolve(type);
kernel.Bind<IHandlerFactory>().To<HandlerFactory>()
.WithConstructorArgument("handlerMethod", handlerMethod);
Of course, if you are processing your handlers asynchronously you have to keep the instance alive until the end of the request rather than disposing it as soon as the handler.Handle() method returns. If that is the case, I suggest you analyze the source code for WebApi to work out what pattern is used to do that when dealing with the System.Web.Http.ApiController.
Related
My question based on InventorySampleApp by Microsoft.
The ServiceLocator contains method Configure() that register Services and ViewModels. With method GetService<T>() we can get it. For example, ProductView.cs:
ViewModel = ServiceLocator.Current.GetService<ProductDetailsViewModel>();
Each *ViewModel contains constructor with interface, for example:
public ProductDetailsViewModel(IProductService productService, IFilePickerService filePickerService, ICommonServices commonServices)
I can't understand the magiс that ViewModel uses to get such interfaces into its constructor. So there are no lines like this:
... = new ProductDetailsViewModel(productService, filePickerService, commonServices)
How does the ViewModel constructor get the required interfaces?
ServiceLocator
public class ServiceLocator : IDisposable
{
static private readonly ConcurrentDictionary<int, ServiceLocator> _serviceLocators = new ConcurrentDictionary<int, ServiceLocator>();
static private ServiceProvider _rootServiceProvider = null;
static public void Configure(IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<ISettingsService, SettingsService>();
serviceCollection.AddSingleton<IDataServiceFactory, DataServiceFactory>();
serviceCollection.AddSingleton<ILookupTables, LookupTables>();
serviceCollection.AddSingleton<ICustomerService, CustomerService>();
serviceCollection.AddSingleton<IOrderService, OrderService>();
serviceCollection.AddSingleton<IOrderItemService, OrderItemService>();
serviceCollection.AddSingleton<IProductService, ProductService>();
serviceCollection.AddSingleton<IMessageService, MessageService>();
serviceCollection.AddSingleton<ILogService, LogService>();
serviceCollection.AddSingleton<IDialogService, DialogService>();
serviceCollection.AddSingleton<IFilePickerService, FilePickerService>();
serviceCollection.AddSingleton<ILoginService, LoginService>();
serviceCollection.AddScoped<IContextService, ContextService>();
serviceCollection.AddScoped<INavigationService, NavigationService>();
serviceCollection.AddScoped<ICommonServices, CommonServices>();
serviceCollection.AddTransient<LoginViewModel>();
serviceCollection.AddTransient<ShellViewModel>();
serviceCollection.AddTransient<MainShellViewModel>();
serviceCollection.AddTransient<DashboardViewModel>();
serviceCollection.AddTransient<CustomersViewModel>();
serviceCollection.AddTransient<CustomerDetailsViewModel>();
serviceCollection.AddTransient<OrdersViewModel>();
serviceCollection.AddTransient<OrderDetailsViewModel>();
serviceCollection.AddTransient<OrderDetailsWithItemsViewModel>();
serviceCollection.AddTransient<OrderItemsViewModel>();
serviceCollection.AddTransient<OrderItemDetailsViewModel>();
serviceCollection.AddTransient<ProductsViewModel>();
serviceCollection.AddTransient<ProductDetailsViewModel>();
serviceCollection.AddTransient<AppLogsViewModel>();
serviceCollection.AddTransient<SettingsViewModel>();
serviceCollection.AddTransient<ValidateConnectionViewModel>();
serviceCollection.AddTransient<CreateDatabaseViewModel>();
_rootServiceProvider = serviceCollection.BuildServiceProvider();
}
static public ServiceLocator Current
{
get
{
int currentViewId = ApplicationView.GetForCurrentView().Id;
return _serviceLocators.GetOrAdd(currentViewId, key => new ServiceLocator());
}
}
static public void DisposeCurrent()
{
int currentViewId = ApplicationView.GetForCurrentView().Id;
if (_serviceLocators.TryRemove(currentViewId, out ServiceLocator current))
{
current.Dispose();
}
}
private IServiceScope _serviceScope = null;
private ServiceLocator()
{
_serviceScope = _rootServiceProvider.CreateScope();
}
public T GetService<T>()
{
return GetService<T>(true);
}
public T GetService<T>(bool isRequired)
{
if (isRequired)
{
return _serviceScope.ServiceProvider.GetRequiredService<T>();
}
return _serviceScope.ServiceProvider.GetService<T>();
}
#region Dispose
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_serviceScope != null)
{
_serviceScope.Dispose();
}
}
}
#endregion
When using dependency injection, the instantiation of objects is moved to a component called Dependency Injection (DI) Container or Inverse of Control (IoC) Container. This component has some kind of registry that contains all known services that can be instantiated. In your example, the serviceCollection is that registry.
Now, whenever a component A needs an instance from the registry, there are two different options:
Directly ask the container for an instance, e. g. ServiceLocator.Current.GetService<ProductDetailsViewModel>(). This is known as the Service Locator Pattern (I'd recommend to forget this immediately).
Rather than asking the container directly, request the dependency via constructor of A (e. g. public A(ProductDetailsViewModel viewModel)).
The second approach can be pushed more and more upwards until the top of the application hierarchy is reached - the so called composition root.
Anyways, in both ways, the container uses the mechanism of Reflection. It is a way of retrieving metadata of classes, methods, properties, constructors, etc. Whenever the container is asked for a certain type (e. g. ProductDetailsViewModel), he uses reflection to get information about its constructor.
Once the constructor is resolved, its dependencies are known as well (IProductService, IFilePickerService, ICommonServices). Since these dependencies are registered within the container (remember the serviceCollection), instances can be created.
This goes on and on until there are no more dependencies and the container can start instantiating and composing all the objects. Finally, there is an instance of ProductDetailsViewModel.
If there is one dependency within the construction chain that is unknown to the container, the instantiation fails.
So basically, the process of instantiation is moved away from your code into the DI container.
Notice that the GetService method calls into ServiceProvider.GetService. This is a library method that takes care of things for you. Underneath the covers, it uses reflection to examine the constructor of the type you request.
For example, when you request a ProductDetailsViewModel, the ServiceLocator can see that it needs object of the types IProductService, IFilePickerService, ICommonServices.
It then looks into its registry of services. For example, the line
serviceCollection.AddSingleton<IProductService, ProductService>();
registers the concrete type ProductService against the interface IProductService, so whenever the ServiceLocator needs to create an IProductService object, it'll use a ProductService object.
This process is called auto-wiring and is described in more details in chapter 12 of Steven van Deursen's and my book about Dependency Injection.
I can't understand the magiс that ViewModel uses to get such interfaces into its constructor.
Indeed, do yourself the favour and learn Pure DI instead of relying on opaque libraries that you don't feel comfortable with.
I've never seen that example code base before, but from the examples posted here, it looks like it's filled with code smells and anti-patterns.
I am writing a service that tells multiple classes implementing the interface IDeviceFinder to go look for connected devices, which the service will put in a cache for other objects to use.
The controller script looks as follows:
private Container _container;
public bool Start()
{
_container.Collection.Register<IDeviceFinder>(
new Assembly[] { Assembly.GetExecutingAssembly() });
_container.Register<IDeviceCache, DeviceCache>(Lifestyle.Singleton);
_container.Register<IDeviceService, DeviceService>();
_container.Verify();
}
Using Simple Injector, the device finders are passed to the DeviceService in the constructor. When the finders find a device they report it back to the service via a delegate. The service then proceeds to put it into the device cache (a singleton).
The device service itself implements the interface IDisposable. Using Dispose the service unsubscribes from the delegates of the device finders.
public class DeviceService : IDeviceService //IDeviceService inherits from IDisposable
{
private IDeviceCache _cache;
private List<IDeviceFinder> _finders = new List<IDeviceFinder>();
public DeviceService(IDeviceCache cache, IDeviceFinder[] finders)
{
this._cache = cache;
this._finders = finders.ToList();
foreach (var finder in this._finders)
{
finder.DeviceFound += AddDeviceToCache;
}
}
public void Dispose()
{
foreach (var finder in this._finders)
{
finder.DeviceFound -= AddDeviceToCache;
}
}
private void AddDeviceToCache(Device device)
{
//...
}
}
However, Simple Injector gives me a warning that the transient DeviceService cannot implement IDisposable.
When I change the lifestyle to be scoped, I get a warning that there is a lifestyle mismatch, because DeviceService (async scoped) depends on IDeviceFinder[] (transient).
How would I fix this error? I don't really want to get rid of the IDisposable interface.
My application creates IDisposable objects that should be reused, so I create a factory that encapsulates the creation and reuse of those objects, code like this:
public class ServiceClientFactory
{
private static readonly object SyncRoot = new object();
private static readonly Dictionary<string, ServiceClient> Clients = new Dictionary<string, ServiceClient>(StringComparer.OrdinalIgnoreCase);
public static ServiceClient CreateServiceClient(string host)
{
lock(SyncRoot)
{
if (Clients.ContainsKey(host) == false)
{
Clients[host] = new ServiceClient(host);
}
return Clients[host];
}
}
}
public class QueryExecutor
{
private readonly ServiceClient serviceClient;
public QueryExecutor(string host)
{
this.serviceClient = ServiceClientFactory.CreateServiceClient(host);
}
public IDataReader ExecuteQuery(string query)
{
this.serviceClient.Query(query, ...);
}
}
What makes me scratch my head is, ServiceClient is IDisposable, I should dispose them explicitly sometime.
One way is implementing IDisposable in QueryExecutor and dispose ServiceClient when QueryExecutor is disposed, but in this way, (1) when disposing ServiceClient, also needs to notify ServiceClientFactory, (2) cannot reuse ServiceClient instance.
So I think it would be much easier to let ServiceClientFactory manage lifetime of all ServiceClient instances, if I go this way, what is the best practice here to dispose all IDisposable objects created by factory? Hook the AppDomain exit event and manually call Dispose() on every ServiceClient instance?
A couple of things to think about here...
Firstly, what you appear to be describing is some variation of the Flyweight pattern. You have an expensive object, ServiceClient, which you want to reuse, but you want to allow consumer objects to create and destroy at will without breaking the expensive object. Flyweight traditionally does this with reference-counting, which might be a bit old hat.
You'll need to make sure that consumers cannot dispose the ServiceClient directly, so you'll also need a lightweight Facade which intercepts the calls to ServiceClient.Dispose and chooses whether to dispose the real object or not. You should hide the real ServiceClient from consumers.
If all that is feasible, you could rewrite your approach as something like:
// this is the facade that you will work from, instead of ServiceClient
public interface IMyServiceClient : IDisposable
{
void Query(string query);
}
// This is your factory, reworked to provide flyweight instances
// of IMyServiceClient, instead of the real ServiceClient
public class ServiceClientFactory : IDisposable
{
// This is the concrete implementation of IMyServiceClient
// that the factory will create and you can pass around; it
// provides both the reference count and facade implementation
// and is nested inside the factory to indicate that consumers
// should not alter these (and cannot without reflecting on
// non-publics)
private class CachedServiceClient : IMyServiceClient
{
internal ServiceClient _realServiceClient;
internal int _referenceCount;
#region Facade wrapper methods around real ServiceClient ones
void IMyServiceClient.Query(string query)
{
_realServiceClient.Query(query);
}
#endregion
#region IDisposable for the client facade
private bool _isClientDisposed = false;
protected virtual void Dispose(bool disposing)
{
if (!_isClientDisposed)
{
if (Interlocked.Decrement(ref _referenceCount) == 0)
{
// if there are no more references, we really
// dispose the real object
using (_realServiceClient) { /*NOOP*/ }
}
_isClientDisposed = true;
}
}
~CachedServiceClient() { Dispose(false); }
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
// The object cache; note that it is not static
private readonly ConcurrentDictionary<string, CachedServiceClient> _cache
= new ConcurrentDictionary<string, CachedServiceClient>();
// The method which allows consumers to create the client; note
// that it returns the facade interface, rather than the concrete
// class, so as to hide the implementation details
public IMyServiceClient CreateServiceClient(string host)
{
var cached = _cache.GetOrAdd(
host,
k => new CachedServiceClient()
);
if (Interlocked.Increment(ref cached._referenceCount) == 1)
{
cached._realServiceClient = new ServiceClient(host);
}
return cached;
}
#region IDisposable for the factory (will forcibly clean up all cached items)
private bool _isFactoryDisposed = false;
protected virtual void Dispose(bool disposing)
{
if (!_isFactoryDisposed)
{
Debug.WriteLine($"ServiceClientFactory #{GetHashCode()} disposing cache");
if (disposing)
{
foreach (var element in _cache)
{
element.Value._referenceCount = 0;
using (element.Value._realServiceClient) { }
}
}
_cache.Clear();
_isFactoryDisposed = true;
}
}
~ServiceClientFactory() { Dispose(false); }
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
// This is just an example `ServiceClient` which uses the default
// implementation of GetHashCode to "prove" that new objects aren't
// created unnecessarily; note it does not implement `IMyServiceClient`
public class ServiceClient : IDisposable
{
private readonly string _host;
public ServiceClient(string host)
{
_host = host;
Debug.WriteLine($"ServiceClient #{GetHashCode()} was created for {_host}");
}
public void Query(string query)
{
Debug.WriteLine($"ServiceClient #{GetHashCode()} asked '{query}' to {_host}");
}
public void Dispose()
{
Debug.WriteLine($"ServiceClient #{GetHashCode()} for {_host} was disposed");
GC.SuppressFinalize(this);
}
}
Secondly, in general, I'd remove the static clauses from the factory and make ServiceClientFactory : IDisposable. You'll see I've done that in my example above.
It may seem like you're just pushing the problem up the chain, but doing so allows you to make this decision on a case-by-case basis, per-something (application, session, request, unit test run -- whatever makes sense) and have the object that represents your something be responsible for the disposal.
If your application would benefit from a single-instance cache then expose a singleton instance as part of an AppContext class (for example) and call AppContext.DefaultServiceClientFactory.Dispose() in your clean-shutdown routine.
The emphasis here is on a clean shutdown. As others have stated, there is no guarantee that your Dispose method will ever actually be called (think power-cycling the machine, mid-run). As such, ideally, ServiceClient.Dispose would not have any tangible side-effects (i.e. beyond freeing resources that would be freed naturally if the process terminates or the machine power-cycles).
If ServiceClient.Dispose does have tangible side-effects, then you have identified a risk here, and you should clearly document how to recover your system from an "unclean" shutdown, in an accompanying user manual.
Thirdly, if both ServiceClient and QueryExecutor objects are intended to be reusable, then let the consumer be responsible for both the creation and disposal.
QueryExecutor only really has to be IDisposable in your sample because it can own a ServiceClient (which is also IDisposable). If QueryExecutor didn't actually create the ServiceClient, it wouldn't be responsible for destroying it.
Instead, have the constructor take a ServiceClient parameter (or, using my rewrite, an IMyServiceClient parameter) instead of a string, so the immediate consumer can be responsible for the lifetime of all objects:
using (var client = AppContext.DefaultServiceClientFactory.CreateServiceClient("localhost"))
{
var query = new QueryExecutor(client);
using (var reader = query.ExecuteReader("SELECT * FROM foo"))
{
//...
}
}
PS: Is there any need for consumers to actually directly access ServiceClient or are there any other objects which need a reference to it? If not, perhaps reduce the chain a little and move this stuff directly to QueryExecutor, i.e. using a QueryExecutorFactory to create flyweight QueryExector objects around cached ServiceClient instances, instead.
Static classes are tricky that way. The constructor for a static class is invoked when an instance member is first invoked. The class is destroyed if and when the application domain is destroyed. If the application terminates abruptly (aborts), there's no guarantee a constructor/finalizer would be called.
Your best bet here is to redesign the class to use a singleton pattern. There are ways to work around this issue, but they require strange, dark magic forces that may cost you your soul.
EDIT: As servy points out, a Singleton won't help here. A destructor is a finalizer, and you won't have any guarantee that it will be called (for a wide variety of reasons). If it were me, I'd simply refactor it to an instantiable class that implements IDisposable, and let the caller deal with calling Dispose. Not ideal, I know, but it's the only way to be sure.
I have the following code block for configuring Ninject in my solution:
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
Contract.Assert(resolver != null);
this.resolver = resolver;
}
public object GetService(Type serviceType)
{
if (resolver == null)
{
throw new ObjectDisposedException("this", "This scope has already been disposed");
}
return resolver.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
{
throw new ObjectDisposedException("this", "This scope has already been disposed");
}
return resolver.GetAll(serviceType);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
IDisposable disposable = resolver as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
resolver = null;
}
}
My opinion is that disposable pattern used here, is not neccessary..
IDependencyScope is IDisposable, but I should only cleanup IDisposable members if I am constructing them, but the injected resolver in the constructor does is not owned (created) by my class, and IResolutionRoot does not derive from/implement IDisposable...
Am I right here ?
(check this article about IDisposable pattern for reference)
(edit):
This is in fact a base class, used by the following class, so removing the IDisposable implementation here cannot be done...
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
My experience with Ninject has been that when it comes to managed objects implementing IDisposable, you don't need to worry so much as they will be disposed off eventually.
However, when if you have disposable objects which are wrappers around unmanaged objects (for example a C# class wrapping around an Office Interop Application object), then you need to take greater care as these will be disposed off eventually by Ninject, but you can't reliably say when.
Sometimes you need to clean up these resources quickly, as other parts of your code may rely on these resources being cleaned up already (for example you may be 'using' one of these objects to create a Workbook, and then need to rename the workbook shortly after, by which point you need the Application object to be released).
In this sort of scenario, I may violate DI principle, and just new up the object when I use it, and dispose of it myself.
I guess just test all of this yourself so you know which objects are suitable to use with Ninject, and which aren't and do so accordingly.
I know that this is the case with Autofac. You shouldn't worry about disposing classes that you have resolved from Autofac because it will call dispose for you. I am pretty sure that Ninject would be similar.
The following miminal implimentation is correct (provided that neither this class or a class that derives from it uses UNmanaged resources - which is rarely the case):
public void Dispose() {
IDisposable disposable = resolver as IDisposable;
if (disposable != null) {
disposable.Dispose();
}
resolver = null;
}
See Minimal IDispose implementation for details.
It is optional as the resolver will be correctly disposed with out it - i.e only necessary in the case when you particularly need to control yourself the release of the resources managed by the resovler (what?).
Suppose that your code is properly designed for DI and IOC through constructor injection of any dependencies. Then whether an IOC container or DI-by-hand is used or not at the composition root doesn't matter much for this problem. I think.
Anyway, I find myself over and over again in a mental struggle with how I should best deal with scope-based services, like transactions or other obviously transient operations. There are constraints that I want to abide to:
Don't let dependency interfaces be IDisposable - it's a leaky abstraction that only the actual implementing type (and the fiddler sitting at the composition root) should care about.
Don't use static service locator types deep down the graph to resolve a dependency - only inject and resolve through the constructor.
Don't pass the IOC container, if any, as a dependency down the graph.
To be able to use using, we need IDisposable, but since a dependency interface shouldn't be IDisposable, how do you get around it to get scoped behavior?
In cases like this I would inject a service factory that creates those scoped services and let the service interface derive from IDisposable. This way the factory would be responsible to create the appropriate service instances and the only point that decides which service implementation to return. You would not need to inject the scoped service anywhere.
public interface ITransaction : IDisposable
{
}
public interface ITransactionFactory
{
ITransaction CreateTransaction();
}
public class Foo
{
private readonly ITransactionFactory transactionFactory;
public Foo(ITransactionFactory transactionFactory)
{
this.transactionFactory = transactionFactory;
}
public void DoSomethingWithinTransaction()
{
using(ITransaction transaction = this.transactionFactory.CreateTransaction())
{
DoSomething();
}
}
}
Most IoC containers today have substantial built-in support for units of work of this nature.
In Autofac, the mechanism that best fits your requirements is the Owned<T> relationship type. You can see it in action (and get some more material) via this article.
Hope this helps,
Nick
Roll your own "garbage collector" maybe? Something that periodically checks IsComplete and/or an LastAccessed attribute of a Dictionary<Transaction> and wastes the "old" ones. It's "a walking memory leak" but either you clean-up explicitly (like through IDisposable) or you workout how to clean-up automatically.
There may be an AOP solution to kicking-off the "gc"... a commit/rollback sounds like a good place to cut... and maybe you won't even need a GC at all... just cleanup the transaction on the way back-up the callstack from commit or rollback.
Good luck with it. I'll be interested to see what solutions (and ideas) other people come-up with.
Cheers. Keith.
I guess another alternative you could use is to wrap your instances with a disposable type, that way it could automatically handle the disposal of the type regardless of whether the type is actually disposable. E.g, I could define something like:
public class DisposableWrapper<T> : IDisposable
{
private readonly T _instance;
private readonly IDisposable _disposable;
public DisposableWrapper(T instance)
{
_instance = instance;
_disposable = instance as IDisposable;
}
public void Dispose()
{
if (_disposable != null)
_disposable.Dispose();
}
public static implicit operator T(DisposableWrapper<T> disposableWrapper)
{
return disposableWrapper._instance;
}
}
(Hopefully with a bit more error handling!)
Given that I know at the point of disposal whether the type is disposable, I can call it accordingly. I can also provide an implicit operator to cast back to the inner type from it. With the above, and a nifty extension method:
public static class DisposableExtensions
{
public static DisposableWrapper<T> Wrap<T>(this T instance)
{
return new DisposableWrapper<T>(instance);
}
}
Let's imagine that I have a service I am injecting into a type, it could be:
public interface IUserService
{
IUser GetUser();
}
I could potentially do something like:
public HomeController(IUserService service)
{
using (var disposable = service.Wrap())
{
var user = service.GetUser();
// I can even grab it again, implicitly.
IUserService service2 = disposable;
}
}
Now regardless of whether that concrete implementation of IUserService is disposable or not, I can still safely work on the assumption that it doesn't matter.
Another quick console example:
class Program
{
static void Main(string[] args)
{
using (var instance = new ClassA().Wrap())
{
ClassA instanceA = instance;
}
using (var instance = new ClassB().Wrap())
{
ClassB instanceB = instance;
}
Console.ReadKey();
}
}
public class ClassA
{
}
public class ClassB : IDisposable
{
public void Dispose()
{
Console.Write("Disposed");
}
}