0

I've taken this approach to injecting a custom resource provider in my ASP.NET MVC application, but I'm having some problems with object lifetime management.

I'm using Castle Windsor, so I have the following implementation of the factory:

public class DefaultResourceProviderFactory : ResourceProviderFactory
{
    public override IResourceProvider CreateGlobalResourceProvider(string classKey)
    {
        // IoC is a static helper class that gives me static access to the
        // container. IoC.Resolve<T>(args...) simply calls container.Resolve<T>(args...).
        return IoC.Resolve<IResourceProvider>(new { resourceType = "Global" });
    }

    public override IResourceProvider CreateLocalResourceProvider(string virtualPath)
    {
        // resourceType
        return IoC.Resolve<IResourceProvider>(new { ResourceType = virtualPath });
    }
}

However, the IResourceProvider I have registered in the container doesn't seem to have its lifetime managed correctly. It has some other dependencies of its own, some of which have somewhat complicated lifestyles (per web request or per transaction), so I've registered the IResourceProvider as transient to ensure that its dependencies are always valid. But the MVC framework is stepping on my toes, keeping a reference to the IResourceProvider across web requests, which causes ObjectDisposedExceptions when its dependencies have been invalidated on the next request.

What I'd like to do, is to make the MVC framework use the factory every time it needs an instance of my IResourceProvider, and - if possible - also to invoke IoC.Release(provider) or something similar when it's done with it.

How do I micro-manage the lifestyle of the custom IResourceProvider in a way that the MVC framework will respect?

Community
  • 1
  • 1
Tomas Aschan
  • 58,548
  • 56
  • 243
  • 402

1 Answers1

1

After searching around for various ways to control the lifetime of the IResourceProvider itself, I decided that it was better to refactor my implementation to utilize the Typed Factory Facility.

My IResourceProvider implementation formerly looked something like this:

public class CachedResourceProvider : IResourceProvider {
    CachedResourceProvider(IResourceRecordRepository repo) { /* ... */ }
    // other members...
}

Now, I changed it to this instead:

public class CachedResourceProvider : IResourceProvider {
    CachedResourceProvider(IResourceRecordRepositoryFactory repo) { /* ... */ }
    // other members...
}

The factory interface is a new one, defined as

public interface IResourceRecordRepositoryFactory {
    IResourceRecord NewInstance();
    void Release(IResourceRecord instance);
}

and every usage of the private _repo instance in the CachedResourceProvider was refactored to three statements: get a repo instance from the factory, use the repo instance to fetch/save something, release the instance through the factory.

I registered them like this:

container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IResourceRecordRepositoryFactory>().AsFactory());

Now, even though MVC is keeping a reference to my resource provider across web requests, the services it uses are re-fetched from the Windsor container each time they're used, so the container is in full control of their lifetime.

Tomas Aschan
  • 58,548
  • 56
  • 243
  • 402