This project is read-only.

How to dispose objects created by Verify()

May 23, 2012 at 7:39 AM

Hi,

I looked at example with SimpleInjectorMVC3 and used it in my project. After a while I noticed that some instances are not disposed. After some debugging I found out that if I call Verify, SimpleInjector tries to create some disposable objects but then it doesn't call Dispose.

Also lets say that the classes don't implement IDisposable or there is other approach how to dispose them...

That leads me to conclusion that Verify should be called only when debugging. Am I right?

May 23, 2012 at 9:06 AM

Simple Injector does not dispose any instances that are resolved from the container. This is by design. The idea behind this is that having to resolve services that need to be disposed should be exceptional, not the default. Having to explicitly release all instances (as some containers require) does complicate normal usage and was therefore left out.

The Verify() method simply iterates all registrations and calls GetInstance() on each and every one on them. Because the container has no notion of disposal, Verify() doesn't either. This however would normally not be a problem since:

  • Just a few services are expected implement IDisposable.
  • Verify should only be called once during the application lifetime, and thus the number of non-disposed objects is small (and it will normally be only one instance per service). Types that really need to be disposed, need to implement a finalizer to guard them against this, and eventually the GC will call finalize on them.
  • Services that are registered as singleton will be kept alive for as long as the container lives, which is normally equal to the lifetime of the AppDomain, so for those services disposing won't be an issue.

Look closely at your design to see if your services really need to implement IDisposable. If they really do, and not disposing services really is a problem, Verify() can indeed not be called during app startup. Best is to only call it inside a unit/integration test (and possibly in #DEBUG mode).

Furthermore, since you want your services to be disposed, you will have to decide when they need to be disposed. There are two extension packages for Simple Injector that implement lifestyles that enable disposing. These are Lifetime Scoping and Per Web Request. Especially the Per Web Request lifestyle is useful in the context of a MVC application. The MVC NuGet package includes the SimpleInjector.Integration.Web.dll, which includes the RegisterPerWebRequest, which enables this lifestyle.

using System.Collections.Generic;
using System.Linq;
namespace MovieTickets
{
    public class Ticket
    {
        TicketBooth booth;
        public Ticket(TicketBooth booth)
        {
            this.booth = booth;
        }

        public int Age { get; set; }

        public bool IsStudent { get; set; }

        public bool IsSenior { get { return this.Age >= 65; } }

        public bool IsChild { get { return this.Age < 13; } }

        public float CalculatePrice(bool isGroup)
        {
            if (this.IsChild)
            {
                return 5.5f;
            }

            if (isGroup)
            {
                return 6f;
            }

            if (this.IsSenior)
            {
                return 6;
            }

            if (this.IsStudent)
            {
                return 8;
            }

            return 11;
        }
    }

    public class TicketBooth : ITicketBooth
    {
        List<Ticket> tickets = new List<Ticket>();

        public int runtime;
        public Day day;
        public bool isParquet;
        public bool is3D;

        public bool IsGroup { get { return this.tickets.Count >= 20; } }

        public void StartPurchase(int runtime, Day day, bool isParquet, bool is3D)
        {
            this.runtime = runtime;
            this.day = day;
            this.is3D = is3D;
            this.isParquet = isParquet;
        }

        public void AddTicket(int age, bool isStudent)
        {
            if (age < 0)
            {
                throw new System.ArgumentException("age");
            }

            this.tickets.Add(new Ticket(this)
            {
                Age = age,
                IsStudent = isStudent,
            });
        }

        public float FinishPurchase()
        {
            float individuelePrijns = this.tickets.Sum(ticket => ticket.CalculatePrice(false) + this.CalculateTicketExtraCosts(false));

            if (this.IsGroup)
            {
                float groupsprijs = this.tickets.Count * 6.00f;

                return groupsprijs < individuelePrijns ? groupsprijs : individuelePrijns;
            }

            return individuelePrijns;
        }

        private float CalculateTicketExtraCosts(bool isGroup)
        {
            float value = 0;

            if (this.is3D)
            {
                value += 3f;
            }

            if (this.runtime > 120)
            {
                value += 1.5f;
            }

            if (this.day == Day.THU && !isGroup)
            {
                value -= 2.0f;
            }

            if (this.day == Day.SAT || this.day == Day.SUN)
            {
                value += 1.5f;
            }

            if (!this.isParquet)
            {
                value += 2.0f;
            }

            return value;
        }
    }
}
Marked as answer by dot_NET_Junkie on 11/3/2013 at 11:53 PM
May 31, 2012 at 6:55 AM

Thank you very much for your detailed response!

In my case I simplified the question a little bit. In fact I return an object with already open connection to database and after some work with the object I close it explicitly. As a helper I added IDisposable so that the connection is called in Dispose(). 

This means, that in case Verify is called, then for each object a new connection would be opened, which is bad. Then for me, it means that (as you suggested), I won't call Verify in Release build.

 

I will also look at the packages for life time management. Thanks for mention, I didn't know about that.