2
votes

As per the Simple Injector documentation, I'm instantiating my repository objects for an MVC application as such:

container.RegisterPerWebRequest<IUserRepository, SqlUserRepository>();
container.RegisterPerWebRequest<IOrderRepository, SqlOrderRepository>();

But I've just found the documentation also states:

In contrast to the default behavior of Simple Injector, these extension methods ensure the created service is disposed (when such an instance implements IDisposable).

https://simpleinjector.codeplex.com/wikipage?title=ObjectLifestyleManagement#PerWebRequest

Question: Does this mean when using RegisterPerWebRequest, my objects need to implement IDisposable so they get disposed at the end of the web request (i.e. below code)?

Side-note: I believe using WebRequestLifestyle, RegisterInitializer, RegisterForDisposal, also requires objects implementing IDisposable.

Example code (interface and implementation) below.

public interface IUserRepository : IDisposable
{
    ...
}

public class SqlUserRepository : IUserRepository, IDisposable
{
    ...
    ...
    ...


    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                _context.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}
2
Note that in general your interfaces should not implement IDisposable; only your implementations should. Otherwise you're leaking implementation details and are violating the Dependency Inversion Principle. - Steven
Did not know this re leaking. I see now. Thanks. - OpcodePete

2 Answers

5
votes

A few side notes here, it seems that you are implementing the full dispose pattern here, but you can simplify this when you make your SqlUserRepository sealed. This allows you to do the following:

public sealed class SqlUserRepository : IUserRepository, IDisposable
{
    public void Dispose()
    {
        _context.Dispose();
    }
}

Since SqlUserRepository is sealed, no one can derive from it and there is therefore:

  • There is no need for the virtual protected Dispose(bool) method.
  • There is no need to call SuppressFinalize, because that is only needed when there is a finalize method, but since you don't implement it and you're sure there's no derived type, you don't need to call it.

There is also no need to have the disposed flag, since you are delegating the dispose to the _context, but it should be resilient to calling dispose multiple times; that is defined in the IDisposable contract.

Further more, if you inject that context object into the constructor of your SqlUserRepository, there is no need at all to implement disposable on the SqlUserRepository. You only have to register that context with a web request lifestyle and Simple Injector will dispose that for you.

4
votes

Disclosure: I have not used SimpleInjector.

From what I gather from reading that, no, you don't need to implement IDisposable.

What it's saying is that, by default, objects that are registered are not disposed of. That is, SimpleInjector won't attempt to call Dispose() if you register the object by means other than per web request.

However, using RegisterPerWebRequest() means that Dispose() will be called if the object is an IDisposable unless you specify otherwise.