Registering Transient Web API Controller with IServiceProvider leads to outofmemoryexception - asp.net-web-api

I've seen numerous examples for setting up a .NET Framework Web API using the DI libraries built for .NET Core (i.e. IServiceProvider). While it all makes sense, I am seeing memory issues with my Web API Controllers. A description of this setup is shown here.
asp.net adding ApiController as service for dependency injection
IServiceProvider uses transient tracking and keeps a list of all disposables. Because the ApiController base class implements IDisposable and is setup as a Transient dependency, the list of disposables will grow indefinitely as subsequent requests are made to each controller. This will create a severely large memory problem. Transient tracking is talked about here.
https://github.com/aspnet/DependencyInjection/issues/456
My question is what is the proper way to register these controllers with the container so memory will not spiral out of control?
I need to use IServiceProvider and cannot use a third-party DI framework.
I have tried to register controllers as scoped, but receive the following error. Any help would be appreciated.
Scoped controller error message

The answer was to instantiate a class implementing IDependencyScope from the BeginScope() method in the DependencyResolver. This prevents a new pointer from being added to the Disposables collection and thereby eliminates the memory leak.
/// <inheritdoc />
public class DefaultDependencyResolver : IDependencyResolver
{
private readonly IServiceProvider _serviceProvider;
/// <inheritdoc />
public DefaultDependencyResolver(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
/// <inheritdoc />
public object GetService(Type serviceType)
{
return _serviceProvider.GetService(serviceType);
}
/// <inheritdoc />
public IEnumerable<object> GetServices(Type serviceType)
{
return _serviceProvider.GetServices(serviceType);
}
/// <inheritdoc />
public IDependencyScope BeginScope()
{
return new DefaultDependencyScope(_serviceProvider.CreateScope());
}
/// <inheritdoc />
public void Dispose()
{
//No-op
}
}
/// <inheritdoc />
public class DefaultDependencyScope : IDependencyScope
{
private readonly IServiceScope _serviceScope;
/// <inheritdoc />
public DefaultDependencyScope(IServiceScope serviceScope)
{
_serviceScope = serviceScope;
}
/// <inheritdoc />
public void Dispose()
{
_serviceScope.Dispose();
}
/// <inheritdoc />
public object GetService(Type serviceType)
{
return _serviceScope.ServiceProvider.GetService(serviceType);
}
/// <inheritdoc />
public IEnumerable<object> GetServices(Type serviceType)
{
return _serviceScope.ServiceProvider.GetServices(serviceType);
}
}
and then register the dependency resolver from the API configuration
//Register controllers with container
foreach (var type in typeof(WebApiConfig).Assembly.GetExportedTypes()
.Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)
.Where(t => typeof(ApiController).IsAssignableFrom(t)))
{
services.AddTransient(type);
}
//Link DI in application to container
var provider = services.BuildServiceProvider();
config.DependencyResolver = new DefaultDependencyResolver(provider);
In my case, I didn't NEED to register any dependencies as singletons. If this is required, there may be additional code needed to conditionally return a scope based on the type.

Related

Capturing and injecting HttpRequestMessage in Web API with Ninject

I've got a class that requires access to the HttpRequestMessage in my Web API service. At the moment, I've got the following code to capture the message in the pipeline and save it for later (based on this and this):
public class ContextCapturingControllerActivator : IHttpControllerActivator
{
private readonly IKernel kernel;
private HttpRequestMessage requestMessage;
public ContextCapturingControllerActivator(IKernel kernel)
{
this.kernel = kernel;
}
public IHttpController Create(HttpRequestMessage requestMessage,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
this.kernel.Rebind<HttpRequestMessage>()
.ToConstant<HttpRequestMessage>(requestMessage);
var controller = (IHttpController)this.kernel.GetService(controllerType);
this.requestMessage = requestMessage;
requestMessage.RegisterForDispose(
new Release(() => this.kernel.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action release;
public Release(Action release)
{
this.release = release;
}
public void Dispose()
{
this.release();
}
}
}
In my composition root, I configure the ControllerActivator:
kernel.Bind<IHttpControllerActivator>()
.To<ContextCapturingControllerActivator>();
The end result is that from the perspective of the configuration, the HttpRequestMessage is "magically" injected wherever it is requested since it is done for us inside the ControllerActivator. I have not been able to inject the message from my composition root. I'm also not crazy about the Rebind since it's there to avoid adding a new binding every time the service is called. I suspect it's due to the singleton nature of the Web API stack, but have not been able to sort out how to deal with that properly.
In general, I cannot use the latest unstable Nuget package of Ninject web api due to the error reported (and ignored) here.
Can anyone suggest the proper way to improve my code to make it a bit more clear and make life easier for future maintainers (and let's face it -- that's probably going to be me).
Thanks.
Here is what I did, but I believe it depends on Web API 2.0+.
I created an instance class that wraps the current context's http request:
public class HttpRequestMessageWrapper
{
private readonly HttpRequestMessage m_httpRequestMessage;
public HttpRequestMessageWrapper()
{
m_httpRequestMessage = HttpContext.Current.Items["MS_HttpRequestMessage"] as HttpRequestMessage;
}
public HttpRequestMessage RequestMessage
{
get
{
return m_httpRequestMessage;
}
}
}
Then I bound the HttpRequestMessage to the property with the ToMethod binding in request scope.
container.Bind<HttpRequestMessage>().ToMethod(ctx => new HttpRequestMessageWrapper().RequestMessage).InRequestScope();
I've tried the method that #Mackers proposed which is the cleanest way.... however, in my specific scenario, it didn't work due to a timing issue. For my case, I needed to inject an object into the apicontroller ctor and that object required the HttpRequestMessage. The HttpContext.Current.Items["MS_HttpRequestMessage"]isn't populated until the controller has been constructed and initialized and I couldn't find any other way to access it. So I resorted to creating a custom DelegatingHandler and rebinding the current request message as they come in.
public class CurrentHttpRequestMessageHandler : DelegatingHandler
{
[SecuritySafeCritical]
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
UpdateScopeWithHttpRequestMessage(request);
return base.SendAsync(request, cancellationToken);
}
internal static void UpdateScopeWithHttpRequestMessage(HttpRequestMessage request)
{
NinjectConfig.GetConfiguredKernel().Rebind<HttpRequestMessage>().ToMethod(ctx => { return request; })
.InRequestScope();
}
}
The GetConfiguredKernel is a static method I created to simply return the static Kernel instance already configured.
public class NinjectConfig
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
private static StandardKernel _kernel;
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static IKernel GetConfiguredKernel()
{
if (_kernel != null)
return _kernel;
return CreateKernel();
}
....
Then register the DelegatingHandler with the HttpConfiguration:
config.MessageHandlers.Add(new CurrentHttpRequestMessageHandler());
Building off of Macker's answer, System.Web has an HttpRequestBase class that you can use and simplify unit testing the code. Anywhere in the code that the request is required, specify the HttpRequestBase type as the constructor parameter and register it with the below method:
Ninject example:
Bind<HttpRequestBase>().ToMethod(context => new HttpRequestWrapper(HttpContext.Current.Request));
Unity example:
container.RegisterType<HttpRequestBase>(new InjectionFactory(_ => new HttpRequestWrapper(HttpContext.Current.Request)));

How can I enrich object composition in StructureMap without invoking setter injection?

I'm trying to build an implementation of the IHttpControllerActivator interface for with with StructureMap, so that I can resolve a dependency of a controller which takes a dependency on the HttpRequestMessage being processed in the MVC Web API pipeline.
My implementation of Create is as follows:
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
return (IHttpController)this.Container
.With(request)
.With(controllerDescriptor)
.GetInstance(controllerType);
}
The Container property is a reference to the StructureMap IContainer instance passed to the activator when it is constructed.
My registration for the controllers uses reflection to obtain all the ApiController implementations:
foreach(var controller in this.GetType().Assembly.GetTypes()
.Where(type => typeof(ApiController).IsAssignableFrom(type)))
{
this.For(controller).Use(controller);
}
Using the debugger, I checked that initialises the controller instances and passes in their dependencies. However, when the ExecuteAsync method is called on the controller, an exception is thrown:
Cannot reuse an 'ApiController' instance. 'ApiController' has to be constructed per incoming message. Check your custom 'IHttpControllerActivator' and make sure that it will not manufacture the same instance.
After some digging and experimentation I discovered this is due to a check performed at the start of ExecuteAsync which checks the Request property of the ApiController to see if it has been assigned a value. If the property has a non-null value, it infers that the controller has already been used to process a request and aborts the operation.
Further to this, I verified that StructureMap attempted to use its setter-injection behaviour when composing the controller and is responsible for Request having a non-null value.
In my registry, I haven't configured any setter-injection, so I'm confused as to why it's being invoked here. A poke around the StructureMap API hasn't yielded any obvious answers as to how I could change the behaviour exhibited.
Am I invoking StructureMap incorrectly? Is there a configuration setting I can leverage to say "never ever assign a property value"?
I think your issue revolves around the way that you are setting up your controllers with StructureMap. In order to get this working correctly, the best way is to hook into the WebAPI stack's dependency injection stack by creating your own implementation of IDependencyResolver. There's a pretty good example of this at http://craigsdevspace.wordpress.com/2012/02/26/using-structuremap-with-web-api/
The basic code, though, might look something like:
IDependencyResolver:
public class _DependencyResolver : _DependencyScope, IDependencyResolver {
public _DependencyResolver(IContainer container) : base(container) { }
public IDependencyScope BeginScope() {
return new _DependencyScope(_container);
}
}
IDependencyScope:
public class _DependencyScope : ServiceLocatorImplBase, IDependencyScope {
protected readonly IContainer _container;
public _DependencyScope(IContainer container) {
if (container == null)
throw new ArgumentNullException("container");
_container = container;
}
public override object GetService(Type serviceType) {
if (serviceType == null)
return null;
try {
return (serviceType.IsAbstract || serviceType.IsInterface)
? _container.TryGetInstance(serviceType)
: _container.GetInstance(serviceType);
} catch {
return null;
}
}
protected override object DoGetInstance(Type serviceType, string key) {
if (string.IsNullOrEmpty(key))
return _container.TryGetInstance(serviceType);
return _container.TryGetInstance(serviceType, key);
}
protected override IEnumerable<object> DoGetAllInstances(Type serviceType) {
return _container.GetAllInstances<object>().Where(s => s.GetType() == serviceType);
}
public IEnumerable<object> GetServices(Type serviceType) {
return _container.GetAllInstances<object>().Where(s => s.GetType() == serviceType);
}
public void Dispose() {
//_container.Dispose();
}
}
To hook these classes up to WebAPI, then, you would add the following to Global.asax:
GlobalConfiguration.Configuration.DependencyResolver =
new _DependencyResolver(ObjectFactory.Container);
And either in Global.asax or in your Bootstrapper, you would add the following:
ObjectFactory.Initialize(x => {
x.Scan(scanner => scanner.AddAllTypesOf<ApiController>());
});
This sets up your StructureMap implementation to use the stack's pre-existing injection structure - which should avoid the problem that you're having.

Mono, ASP.NET MVC 3, Ninject and a default constructor required

I have a working Visual Studio project that I want to run o Mac with Mono and MonoDevelop.
The project is an ASP.NET MVC 3 application with Ninject MVC that basically inject on controller some interface implementations.
After add all ASP.NET MVC dlls and Ninject dependencies to the project, it compiles successfully. But when I go to run it, I have the error:
Default constructor not found for type WebActivatorTest.Controllers.HomeController.
My controller has the following code:
public class HomeController : Controller
{
INotifier _notifier;
public HomeController(INotifier notifier_)
{
_notifier = notifier_;
}
public ActionResult Index()
{
ViewBag.Name = _notifier.Person();
return View();
}
}
I dont wanna have an empty constructor, cause I now have an AppStart code registering my interface:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<WebActivatorTest.Models.INotifier>().To<WebActivatorTest.Models.Notifier>();
}
This code works perfectly on Windows/Visual Studio but does not work on Mono.
Could some one help me?
The full error is:
Server Error in '/' Application
Default constructor not found for type WebActivatorTest.Controllers.HomeController.
Description: HTTP 500. Error processing request.
Stack Trace:
System.MissingMethodException: Default constructor not found for type WebActivatorTest.Controllers.HomeController.
at System.Activator.CreateInstance (System.Type type, Boolean nonPublic) [0x00000] in <filename unknown>:0
at System.Activator.CreateInstance (System.Type type) [0x00000] in <filename unknown>:0
at System.Web.Mvc.DefaultControllerFactory+DefaultControllerActivator.Create (System.Web.Routing.RequestContext requestContext, System.Type controllerType) [0x00000] in <filename unknown>:0
Version information: Mono Runtime Version: 2.10.9 (tarball Tue Mar 20 15:31:37 EDT 2012); ASP.NET Version: 4.0.30319.1
you can add default constructor
public HomeController()
{
}
But i think, you wrong activate Ninject for controllers. You need register ninject factory. Make sure your code in Global.asax like below:
public class MvcApplication : NinjectHttpApplication
{
/// <summary>
/// Registers the global filters.
/// </summary>
/// <param name="filters">The filters.</param>
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
/// <summary>
/// Registers the routes.
/// </summary>
/// <param name="routes">The routes.</param>
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
return kernel;
}
/// <summary>
/// Called when the application is started.
/// </summary>
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
Also, for examples you can see sample code on MVC3 here
Or you could use the MVC extensions for ninject, as detailed here
I'm assuming this will work with Mono
I'm coming a little late to the party, but this solution helped me.
Override the default constructor:
public HomeController() : this(new Notifier())
{
}
public HomeController(INotifier notifier_)
{
_notifier = notifier_;
}

ninject dependency resolver and service locator implementation

I am learning ASP.NE4 MVC3. I have created a NinjectDependencyResolver class, but I want to know how I would go about implementing the ServiceLocator class. Currently I get this error "The type SportsStore.WebUI.Infrastructure.NinjectDependencyResolver does not appear to implement Microsoft.Practices.ServiceLocation.IServiceLocator.
Parameter name: commonServiceLocator".
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
RegisterDependencyResolver();
//ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
}
private void RegisterDependencyResolver()
{
var kernel = new StandardKernel();
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
NinjectDepencyResolver cs
public class NinjectDependencyResolver
{
private readonly IKernel _kernel;
public NinjectDependencyResolver(IKernel kernel)
{
_kernel = kernel;
}
public object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _kernel.GetAll(serviceType);
}
catch (Exception)
{
return new List<object>();
}
}
Your NinjectDependencyResolver must inherit from IDependencyResolver so your code should look like this:
public class NinjectDependencyResolver : IDependencyResolver
I would not do it like that. For one thing, Mark Seemann's book "Dependency Injection in .NET" clearly shows that Service Locator is actually an anti-pattern.
At any rate try not to bloat your global.asax file
If you instead used Nuget and got the latest version of NinjectMVC3 , you should end up with a clean Application_Start method
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
However, if you want to you can add in this line into the end of that method as I believe this is what Adam and Steve do in the Sportstore application in the Apress MVC3 book.
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
Since that book was released, Ninject released newer versions that make it much easier, in fact I would guarantee that the Apress MVC4 book that ends up coming out will show the simpler way. The simple way is use nuget and get NinjectMVC3 , then it will have an App_Start folder which will run the files in them at start of the application.
Here is an example of it with some bindings
using Products.Data.Abstract;
using Products.Data.Concrete;
using Products.Data.Infrastructure;
[assembly: WebActivator.PreApplicationStartMethod(typeof(ProductsWeb.App_Start.NinjectMVC3), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(ProductsWeb.App_Start.NinjectMVC3), "Stop")]
namespace ProductsWeb.App_Start
{
using System.Reflection;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Mvc;
public static class NinjectMVC3
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule));
DynamicModuleUtility.RegisterModule(typeof(HttpApplicationInitializationModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IProductsRepository>().To<FakeProductsRepository>();
kernel.Bind<MovieRepository>().To<MovieRepository>();
}
}
}
Why not just use the official MVC Integration extension for Ninject, and the Common Service Locator implementation that comes in the official main distribution of Ninject (the dll is included in the build downloads)?

Sterling serialization problem on Windows Phone 7

I have a problem with Sterling Database for Windows Phone. I implemented the database step by step in my wp7app, but it doesn't serialize my data when new entities are saved. For example: I serialize credentials using sterling database:
var userCredentials = new UserCredentials(userName, password);
App.Database.Save(userCredentials);
App.Database.Flush();
But when the application is reactivated (or re-launched) Sterling doesn't return any values from isolated storage:
var firstOrDefault = App.Database.Query<UserCredentials, string>()
.ToList()
.FirstOrDefault();
My ActivateEngine method looks are standard and TableDefinition is:
CreateTableDefinition< UserCredentials, string >(t => t.UserName),
Why is sterling database doesn't serialize my data? Everything seems to be implemented fine. Please help.
Are you activating and registering the database on startup and diposing on completion as described in the Quickstart?
My personal preference is to use an application service similar to the following:
namespace MyApp.Data
{
using System.Windows;
using Wintellect.Sterling;
using Wintellect.Sterling.IsolatedStorage;
///
/// Defines a an application service that supports the Sterling database.
///
public class SterlingDatabaseService : IApplicationService, IApplicationLifetimeAware
{
public static SterlingDatabaseService Current { get; private set; }
public ISterlingDatabaseInstance Database { get; private set; }
private SterlingEngine _engine;
///
/// Called by an application in order to initialize the application extension service.
///
/// Provides information about the application state.
public void StartService(ApplicationServiceContext context)
{
Current = this;
_engine = new SterlingEngine();
}
///
/// Called by an application in order to stop the application extension service.
///
public void StopService()
{
_engine = null;
}
///
/// Called by an application immediately before the event occurs.
///
public void Starting()
{
_engine.Activate();
Database = _engine
.SterlingDatabase
.RegisterDatabase(new IsolatedStorageDriver());
}
///
/// Called by an application immediately after the event occurs.
///
public void Started()
{
return;
}
///
/// Called by an application immediately before the event occurs.
///
public void Exiting()
{
_engine.Dispose();
}
///
/// Called by an application immediately after the event occurs.
///
public void Exited()
{
return;
}
}
}
If you use this approach, don't forget to add an instance in App.xaml:
<Application.ApplicationLifetimeObjects>
<!-- Required object that handles lifetime events for the application. -->
<shell:PhoneApplicationService Activated="Application_Activated"
Closing="Application_Closing"
Deactivated="Application_Deactivated"
Launching="Application_Launching" />
<data:SterlingDatabaseService />
</Application.ApplicationLifetimeObjects>

Resources