Search code examples
dryioc

How to get implicitly created scope from resolved instance in DryIoc?


We've got Unit of Work as an external dependency of ViewModel. Both ViewModel and UnitOfWork implement IDisposable interface for cleanup. ViewModel uses UnitOfWork, but does not dispose it:

public class UnitOfWork: IDisposable
{
    public void Dispose() 
    { 
        // some clean-up code here. 
    }
}

public class ViewModel: IDisposable
{
    private readonly UnitOfWork _unitOfWork;

    public ViewModel(UnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
    public void Dispose() 
    {
        // some clean-up code here, but NO _unitOfWork.Dispose() because ViewModel does not create UnitOfWork.
    }
}

ViewModel is transient: new instance should be created every time DI container's Resolve() method is called. ViewModels are disposed by an external code that has no accces to DI container. For now, UnitOfWork is scoped: only one instance should be created for one ViewModel and Dispose() should be called on ViewModel's Dispose(). We use DryIoc 4.0.7. The documentation says that current resolution scope can be injected to constructor as IDisposable object. So we change our ViewModel:

public class ViewModel: IDisposable
{
    private readonly UnitOfWork _unitOfWork;
    private readonly IDisposable _scope;

    public ViewModel(UnitOfWork unitOfWork, IDisposable scope)
    {
        _unitOfWork = unitOfWork;
        _scope = scope;
    }
    public void Dispose() 
    {
        // some clean-up code here.
        _scope.Dispose(); // we also dispose current scope.
    }
}

Our composition root now looks like this:

var container = new Container();
container.Register<UnitOfWork>(reuse: Reuse.Scoped);
container.Register<ViewModel>(
    setup: Setup.With(openResolutionScope: true, allowDisposableTransient: true));

I can't see how this code is different from the provided one in the documentation, but it throws an exception on Resolve() method:

DryIoc.ContainerException: 'Unable to resolve IDisposable as parameter "scope"
  in ViewModel FactoryId=53 IsResolutionCall
  from Container with Scope {Name={ServiceType=ViewModel}}
 with Rules with {AutoConcreteTypeResolution}
 with Made={FactoryMethod=ConstructorWithResolvableArguments}
Where no service registrations found
  and no dynamic registrations found in 0 of Rules.DynamicServiceProviders
  and nothing found in 1 of Rules.UnknownServiceResolvers'

What are we missing? Is the documentation outdated? Is there another way to get implicitly created scopes to dispose them?


Solution

  • This documentation is outdated - I have opened the respective issue.

    The current scope can be injected as IResolverContext:

    public ViewModel(UnitOfWork unitOfWork, IResolverContext scopedContext) {...}