Reputation: 1107
Controller
public class LocationsController : ApiController
{
private readonly IMediator _mediator;
public LocationsController(IMediator mediator)
{
_mediator = mediator;
}
public IEnumerable<Place> Get()
{
return _mediator.Send(new GetLatestMapData<Place>());
}
}
On first request of Get() action, the Handler is instantiated by SimpleInjector and executed correctly.
On the second request (F5 in browser for e.g.), it fails with :
Handler was not found for request of type ....
Container or service locator not configured properly or handlers not registered with your container.
and inner exception of:
Cannot access a disposed object.
Object name: 'The ThreadLocal object has been disposed.'
OWIN Startup
public class Startup
{
public void Configuration(IAppBuilder app)
{
// SimpleInjector
var container = CompositionRoot.CreateContainer();
var config = GlobalConfiguration.Configuration;
config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
// Routing
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
config.EnsureInitialized();
app.UseWebApi(config);
}
}
SimpleInjector IPackage for WebAPI project
public class Installer : IPackage
{
public void RegisterServices(Container c)
{
c.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
c.RegisterWebApiControllers(GlobalConfiguration.Configuration);
}
}
I think what's happening is the Handler is correctly created, and then disposed after the first request. Now, I don't know why, but on subsequent requests, the Handler isn't re-created. I know this because if I change the WebApiRequestLifestyle to 'not dispose when scope ends', it works for every request:
c.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle(false
/*disposeInstanceWhenScopeEnds*/);
Questions
disposeInstanceWhenScopeEnds
parameter set to false?(And thank you for reading)
Upvotes: 0
Views: 1621
Reputation: 658
You need to arrange your Lifetime scoped
Code:
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
container.Options.LifestyleSelectionBehavior = new WebApiInjectionLifestyle();
internal class WebApiInjectionLifestyle : ILifestyleSelectionBehavior
{
public Lifestyle SelectLifestyle(Type serviceType, Type implementationType)
{
return Lifestyle.Scoped;
}
}
More Detail
https://simpleinjector.readthedocs.io/en/latest/lifetimes.html
Upvotes: 0
Reputation: 93
This link provides good guidance on dependency resolution and using the IDependencyResolver / IDependencyScope Interfaces.
Immediately you will see that they touch on life spans which tend to get a little tricky.
This section in particular is interesting:
Dependenecy Scope and Controller Lifetime
Controllers are created per request. To manage object lifetimes, IDependencyResolver uses the concept of a scope.
The dependency resolver attached to the HttpConfiguration object has global scope. When Web API creates a controller, it calls BeginScope. This method returns an IDependencyScope that represents a child scope.
Web API then calls GetService on the child scope to create the controller. When request is complete, Web API calls Dispose on the child scope. Use the Dispose method to dispose of the controller’s dependencies.
Conventionally bootstrapping a service would occur once during the app start-up and as you know resolve any dependencies at that time. Only when the worker process was shutting down (no activity, for example) would this then invoke dispose.
Ordinarily I think it is quite normal for resolved instances to remain for the life cycle unless it is imperative that they are destroyed after use. But the example given explains that we must correctly dispose once the request is complete. So I would recommend that you dispose of your instances correctly using the examples provided as guidance.
This helped me when working with IoC and WebApi. I hope this helps!
Upvotes: 0