I am creating a custom ActionResult for my controllers because I’ve noticed a lot of repeated code that could be made reusable. It looks something like this:
public ExtendedViewResult<T> : ActionResult
{
protected T Model { get; set; }
protected IModelExtender<T> Extender { get; set; }
public ExtendedActionResult(T model, IModelExtender<T> extender)
{
this.Model = model;
this.Extender = extender;
}
}
public class BaseController : Controller
{
public ExtendedViewResult<T> ExtendedView<T>(T model)
{
// I need to create the result here, but how?
var result = new ExtendedViewResult<T>(model, ???????);
return result;
}
}
The problem I am having is that I’m not sure how to construct my ExtendedViewResult object. Since the interface is generic I want to use Dependency Injection to get the proper object, but I’m not sure how to do that since I’m constructing the object myself.
I am using Ninject and Ninject.MVC3 and the default Nuget package creates a Bootstrapper class for me, and when I access the Bootstrapper.Kernel property I get the following warning:
Ninject.Web.Mvc.Bootstrapper.Kernel is obsolete. Do not use Ninject as Service Locator.
If I’m not supposed to access the kernel directly, then how can I change my code so that I can get the appropriate concrete class?
EDIT
Here is the ninject bootstrapper code. The only method I added is the GetInstance()
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();
}
// I ADDED THIS CODE, EVERYTHING ELSE IS AUTO-GENERATED
// BY THE NUGET PACKAGE
public static T GetInstance<T>()
{
return bootstrapper.Kernel.Get<T>();
}
/// <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)
{
}
}
Sorry this will be dry on actual code – I’ve not used ninject much, but other DI containers have this solution, and I’m sure ninject will have this construct as well.
The issue is that you are constructing the object itself. When you’re really using a DI container and following IoC, anytime you see the keyword
newshould be a red flag – and using the container as a service locator is a yellow one.So how do we get rid of the ‘new’, since you need a new object? The answer is to have your
BaseControllertake a dependency on a factory that can create anExtendedViewResult. In Autofac (my container of choice), that would be as simple as having aFunc<ExtendedViewResult>injected. I would be surprised if Ninject doesn’t have the same. In fact, looks like it does – this ninject wiki page points to this blog post on Ninject.Extensions.Factory.So that means your code for the Controller could look like this:
If you REALLY want to have a generic method do the creation in your base class, then you will probably need to go the explicit factory interface route from the blog post linked above. With this style code though, you would not need it in most cases, and your controllers explicitly declare the dependencies they need.