Reputation: 10096
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
.
Upvotes: 2
Views: 1745
Reputation: 10096
I had forgotten to add .Singleton()
to expression.For<IDocumentStore>().Use(documentStore);
. The code above works as expected with this modification.
Upvotes: 2