views:

82

answers:

1

BIG EDIT: This problem is probably being caused by MEF!

I'm using a service oriented architecture and have all my MVC controllers perform actions through the services.

I have a base service that looks like this:

public abstract class BaseService
{    
     protected MyObjectModel context;

     public BaseService()
     {
          context = new MyObjectModel();
     }
}

I then have services that inherit

[Export(typeof(IEmployeeService))]    
public class EmployeeService : BaseService, IEmployeeService
    {
         public void NewEmployee(Employee newEmployee)
         {
              context.Employees.AddObject(newEmployee);
              context.SaveChanges();
         }
    }

I have my controllers also inheriting from a base class that provides access to all the required services so they can just call:

EmployeeService.AddEmployee(new Employee() { Name = "JohnDoe"});

This all worked wonderfully until I started seeing that the ObjectContext wasn't accurately reflecting the database upon construction.

I put a breakpoint in the BaseService constructor and using Sql Server's Profiler saw that the brand new MyObjectModel wasn't even hitting the DB but pulling the data out of some cache presumably?

I stumbled upon the MergeOption property of the collections in the context and changing that made sure the data was fresh, but now I need to use that everytime I create a new service method that returns entities!

EDIT: I've been stumbling along until I realised that my issues were probably being caused by MEF.

I have overridden the default ControllerFactory and implemented one that uses MEF to instantiate the services. What I'm probably seeing is MEF keeping the objects alive between calls.

So

1) Where can I read more on this behaviour? And what can I do to stop it and force a fresh composition every time the object is called?

Thanks.

A: 

I solved this issue eventually after hours of pulling out my hair.

My implementation of ControllerFactory looked like this.

public class ControllerFactory : IControllerFactory
    {
        CompositionContainer container;
        DefaultControllerFactory controllerFactory;

        public ControllerFactory()
        {
            container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            controllerFactory = new DefaultControllerFactory();
        }

        public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            var controller = controllerFactory.CreateController(requestContext, ControllerName);

            container.ComposeParts(controller);

            return controller;
        }

        public void ReleaseController(IController controller)
        {
            var disposable = controller as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }
    }

And I called this line in my Application Startup.

ControllerBuilder.Current.SetControllerFactory(new ControllerFactory());

What was happening was that the controller factory was only being initialised once per AppDomain cycle and therefore my composition container was as well. My service classes weren't marked specifically for Shared or Non Shared usage, so the container held onto a reference of each one. Every time the ControllerFactory created a new controller on each call it would populate the service properties with the references it still held from the last call, including the old ObjectContext which was resulting in the mismatch in data.

My entire problem was solved by adding

[PartCreationPolicy(CreationPolicy.NonShared)]

to each service enforcing a fresh version each time.

Now I'm left to wonder if MEF is STILL holding onto thos references, because that ObjectContext is not a small thing to hold onto. Is this a memory leak waiting to happen?

robertFall
It is probably better to create a separate CompositionContainer for each request. Then you won't have to worry about MEF holding on to the references (which it will if the parts implement IDisposable). You can create the catalog once and then create a CompositionContainer using that catalog for each request.
Daniel Plaisted
What are the costs involved in creating a CompositionContainer in each request? Are they small enough to ignore? Sounds like this is the right path to take...
robertFall
And at what stage should I be creating this container, in the controller factory? I want to create a single ObjectContext per request as well and share it amongst my services. Is the controller factory the place to do so?
robertFall