Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Structuremap PerRequest lifecycle

I want to inject an instance into structuremap on the fly (i.e. outside of a registry/configuration) that lives for the life of the request.

Currently I'm doing this in the HandleBeginRequest event of an IHttpModule:

container.Configure(x => x.For<IMyClass>()
  .LifecycleIs(Lifecycles.GetLifecycle(InstanceScope.PerRequest))
  .Use(new MyClass()));

However, if at some point in the application's life I do:

ObjectFactory.WhatDoIHave();

I see as many configured instances for IMyClass as there have been requests (or at least a significant amount).

Thinking about it, this sort of makes sense given the code I have.

Is there a better way to inject an instance into the container just for the life of the current request in a way that doesn't pollute the whole container?

Thanks

like image 680
Andrew Bullock Avatar asked Mar 29 '11 15:03

Andrew Bullock


2 Answers

Your problem is that you're registering the type in the container once per request, which is building up on the registrations. Configuring the container should ideally be made once in the application's lifecycle - typically in the Application_Start event for web applications.

Structuremap allows you to specify a creational function that is invoked upon creating the object, which will let you configure advanced object creation steps.

Instead of your current call to Configure in the Begin_Request event, stick the following in the container configuration during Application_Start.

For<IMyClass>().HttpContextScoped().Use(() => new MyClass());

Notice the lambda in the Use method. The lambda can contain any logic needed in order to create the object and it will be invoked one per lifecycle (per request in the case of HttpContext lifecycle).

like image 81
PHeiberg Avatar answered Sep 30 '22 17:09

PHeiberg


I went with this in the end

For<IRequestContextStorage>()
    .HybridHttpOrThreadLocalScoped()
    .Use<RequestContextStorage>();

For<MyClass>()
    .Use(c => c.GetInstance<IRequestContextStorage>().Get<MyClass>());

...

public class RequestContextStorage : IRequestContextStorage
{
    readonly IDictionary<Type, object> hash;

    public RequestContextStorage()
    {
        this.hash = new Dictionary<Type, object>();
    }

    public T Get<T>() where T : class
    {
        if(this.hash.ContainsKey(typeof(T)))
            return this.hash[typeof (T)] as T;

        return null;
    }

    public void Set<T>(T instance)
    {
        this.hash[typeof (T)] = instance;
    }
}

...


static void HandleBeginRequest(object sender, EventArgs e) {

    ObjectFactory.Get<IRequestContextStore>().Set(new MyClass());

}
like image 35
Andrew Bullock Avatar answered Sep 30 '22 17:09

Andrew Bullock