2

As the title says, I'm trying to use dependency injection using StructureMap, Web Api and HybridHttpOrThreadLocalScoped instance of a RavenDB session.

For that I'm using a IHttpControllerActivator, see code below.

public class StructureMapControllerActivator : IHttpControllerActivator
{
    private readonly IContainer _container;

    public StructureMapControllerActivator(IContainer container)
    {
        if (container == null) throw new ArgumentNullException("container");
        _container = container;
    }

    public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        try
        {
            var scopedContainer = _container.GetNestedContainer();
            scopedContainer.Inject(typeof(HttpRequestMessage), request);
            request.RegisterForDispose(scopedContainer);
            return (IHttpController)scopedContainer.GetInstance(controllerType);
        }
        catch (Exception e)
        {
            // TODO : Logging
            throw e;
        }
    }
}

In my global.asax I wire up the IHttpControllerActivator like this:

GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new StructureMapControllerActivator(ApplicationContainer));

And this is my configuration for StructureMap:

expression.For<IDocumentStore>().Use(documentStore);
expression.For<IDocumentSession>()
    .HybridHttpOrThreadLocalScoped()
    .Use(container =>
    {
        var store = container.GetInstance<IDocumentStore>();                        
        return store.OpenSession();
    });

In my ApiController I have a constructor like this:

public MyApiController(IDocumentSession session) {
    _session = session;
}

When I make the first Request I get an instance of the DocumentSession, but the second Request throws an HttpError exception on this line return store.OpenSession(). The exception states that the object is already disposed and cannot be used. This is the complete exception:

{
  "$type": "System.Web.Http.HttpError, System.Web.Http",
  "message": "An error has occurred.",
  "exceptionMessage": "StructureMap Exception Code:  207\nInternal exception while creating Instance '6d9a72a3-3044-495a-909c-dd9fe7527c80' of PluginType Raven.Client.IDocumentSession, Raven.Client.Lightweight, Version=2.5.0.0, Culture=neutral, PublicKeyToken=37f41c7f99471593.  Check the inner exception for more details.",
  "exceptionType": "StructureMap.StructureMapException",
  "stackTrace": "   at BrickPile.Mvc.StructureMapControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) in c:\\Users\\maqe\\Documents\\Visual Studio 2013\\Projects\\brickpile\\BrickPile\\Mvc\\StructureMapWebApiDependencyResolver.cs:line 61\r\n   at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()",
  "innerException": {
    "$type": "System.Web.Http.HttpError, System.Web.Http",
    "message": "An error has occurred.",
    "exceptionMessage": "The document store has already been disposed and cannot be used\r\nObject name: 'EmbeddableDocumentStore'.",
    "exceptionType": "System.ObjectDisposedException",
    "stackTrace": "   at Raven.Client.Document.DocumentStore.OpenSession(OpenSessionOptions options) in c:\\Builds\\RavenDB-Stable\\Raven.Client.Lightweight\\Document\\DocumentStore.cs:line 355\r\n   at BrickPile.DefaultBrickPileBootstrapper.<>c__DisplayClassc.<ConfigureApplicationContainerInternal>b__a(IContext container) in c:\\Users\\maqe\\Documents\\Visual Studio 2013\\Projects\\brickpile\\BrickPile\\DefaultBrickPileBootstrapper.cs:line 294\r\n   at StructureMap.Pipeline.LambdaInstance`1.build(Type pluginType, BuildSession session) in c:\\BuildAgent\\work\\767273992e840853\\src\\StructureMap\\Pipeline\\LambdaInstance.cs:line 25"
  }
}

Can anyone help me with what I am missing here?

I forgot to mention that I use an IHttpModule for releasing and disposing all http scoped objects in Application_EndRequest.

3
  • I added .Singleton() to expression.For<IDocumentStore>().Use(documentStore); and now it seems to work with the exact same code I posted in my question. Can anyone confirm the solution? Commented Feb 18, 2014 at 20:08
  • 1
    That is correct. The IDocumentStore instance should be a singleton and the IDocumentSession instance should be HTTP scoped. By default StructureMap creates a new instance of the class every time. Commented Feb 18, 2014 at 21:55
  • Sure you want to throw e;? Most every time, it should just be throw; as you're losing your call stack. Commented Feb 20, 2014 at 19:30

1 Answer 1

2

I had forgotten to add .Singleton() to expression.For<IDocumentStore>().Use(documentStore);. The code above works as expected with this modification.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.