Question

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.

Was it helpful?

Solution

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top