MVC5, Web API 2 and Ninject - asp.net-web-api

I have created a new MVC5 project with Web API 2, I then added the Ninject.MVC3 package from NuGet.
Constructor injection is working fine for the MVC5 controllers, but i am getting an error when trying to use it with the Web API Controllers.
An error occurred when trying to create a controller of type 'UserProfileController'. Make sure that the controller has a parameterless public constructor.
Constructor for working MVC5 controller:
public class HomeController : Controller
{
private IMailService _mail;
private IRepository _repo;
public HomeController(IMailService mail, IRepository repo)
{
_mail = mail;
_repo = repo;
}
}
Constructor for non-working Web API Controller:
public class UserProfileController : ApiController
{
private IRepository _repo;
public UserProfileController(IRepository repo)
{
_repo = repo;
}
}
Below is the full NinjectWebCommon.cs file:
[assembly: WebActivator.PreApplicationStartMethod(typeof(DatingSite.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(DatingSite.App_Start.NinjectWebCommon), "Stop")]
namespace DatingSite.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using DatingSite.Services;
using DatingSite.Data;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
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();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
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)
{
#if DEBUG
kernel.Bind<IMailService>().To<MockMailService>().InRequestScope();
#else
kernel.Bind<IMailService>().To<MailService>().InRequestScope();
#endif
kernel.Bind<SiteContext>().To<SiteContext>().InRequestScope();
kernel.Bind<IRepository>().To<Repository>().InRequestScope();
}
}
}

The Ninject.Web.WebApi NuGet package has just been released. From now on the preferred solution is using that package.
I couldn't find any related documentation but after installing the package everything worked for me.
Install-Package Ninject.Web.WebApi
After installation both the normal MVC and the API controller instances are provided by Ninject.
If you have Ninject.Web.Common already installed make sure to save your bindings from NinjectWebCommon.cs and let Nuget rewrite NinjectWebCommon.cs during install and put back your bindings when finished.
As pointed out in the comments depending on your execution context you will need one of the following packages as well:
Ninject.Web.WebApi.WebHost
Ninject.Web.WebApi.OwinHost
Ninject.Web.WebApi.Selfhost
The most common scenario is IIS for that pick the WebHost package.
In the case you start an IIS MVC5 web app from scratch and want to use Ninject install the following packages:
Ninject - Ninject core dll
Ninject.Web.Common - Common Web functionality for Ninject eg. InRequestScope()
Ninject.MVC5 - MVC dependency injectors eg. to provide Controllers for MVC
Ninject.Web.Common.WebHost - Registers the dependency injectors from Ninject.MVC5 when IIS starts the web app. If you are not using IIS you will need a different package, check above
Ninject.Web.WebApi WebApi dependency injectors eg. to provide Controllers for WebApi
Ninject.web.WebApi.WebHost - Registers the dependency injectors from Ninject.Web.WebApi when IIS starts the web app.

You have this problem because Controller and ApiController use different Dependency Resolvers. Solution is very simple.
At first create new classes of Dependency Resolver and Dependency Scope. You can use this:
public class NinjectResolver : NinjectScope, IDependencyResolver
{
private readonly IKernel _kernel;
public NinjectResolver(IKernel kernel)
: base(kernel)
{
_kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectScope(_kernel.BeginBlock());
}
}
public class NinjectScope : IDependencyScope
{
protected IResolutionRoot resolutionRoot;
public NinjectScope(IResolutionRoot kernel)
{
resolutionRoot = kernel;
}
public object GetService(Type serviceType)
{
IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
return resolutionRoot.Resolve(request).SingleOrDefault();
}
public IEnumerable<object> GetServices(Type serviceType)
{
IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
return resolutionRoot.Resolve(request).ToList();
}
public void Dispose()
{
IDisposable disposable = (IDisposable)resolutionRoot;
if (disposable != null) disposable.Dispose();
resolutionRoot = null;
}
}
After that, add next line to method CreateKernel() in NinjectWebCommon
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);

I had the same problem.
After installation of the following NuGet packages:
Ninject
Ninject.web.WebApi
Ninject.web.WebApi.WebHost
Ninject.MVC3
Ninject.web.Common
Ninject.web.Common.WebHost
everything works fine

I'm found that assembly Ninject.Web.WebApi.dll define own DependencyResolver and register it with kernel in class Ninject.Web.WebApi.WebApiModule automatically.
So I simply add to NinjectWebCommon.CreateKernel one line...
GlobalConfiguration.Configuration.DependencyResolver =
kernel.Get<System.Web.Http.Dependencies.IDependencyResolver>();
Finally my project has following dependencies:
Ninject 3.2.0
Ninject.Web.Common 3.2.0
Ninject.Web.WebApi 3.2.4

Just for others, who might have a similar set up to me, and got here via google like I did.
I had multiple applications using one WebApi project. I would get the above error if I hadn't included the binding in the RegisterServices method. So before pulling your hair out, just check you have the binding set up. The error doesn't tell you you have missing bindings. Which it would if the Application is in the same project as the WebApi.

I recently had to get Web Api 2 working with so I can answer that part of the question.
These are the nuget packages needed for Web Api 2-
Ninject
Ninject.Web.Common
Ninject.Web.Common.WebHost
Ninject.Web.WebApi
WebActivatorEx
Then edit NinjectWebCommon.CreateKernel(..) including
RegisterServices(kernel);
// the next line is the important one
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
I've written a more detailed post about this - http://NoDogmaBlog.bryanhogan.net/2016/04/web-api-2-and-ninject-how-to-make-them-work-together/ including a full solution to download.

You are supposed to install these packages from Nuget in webAPI project.
Ninject
Ninject.Web.Common
Ninject.Web.Common.WebHost
Ninject.Web.WebApi
Ninject.Web.WebApi.WebHost
Then you must install the Ninject package in the Repository project as well (the version must be the same as in API project). I had the same issue when there was a different version installed for Ninject.

I had this issue in a solution where the project in which I was using Ninject was not using Web API (I have 6 projects so far in my solution). I kept on getting the dreaded "parameterless constructor required" which obviously meant when I added it the Ninject injection was not getting instantiated as it was dropping into the empty constructor. I tried various solutions but in the end I checked my Ninject packages and saw that the Ninject.Web.Webapi package was installed. I uninstalled this and did a clean and rebuild. This solved the issue. My other lower level project was referencing the Ninject.Web.Api package and stupidly I had installed that into my Web front end project.
I hope this may help other people who have tried all the Stack solutions and got no where.

Related

Am I using correct lifetime managers for dependency injection?

I have an asp.net web api application that uses Unity dependency injection libraries from MS Unity.AspNet.WebApi and Unity nuget packages. Also, the application uses Entity Framework version 6 database context for ORM and a generic repository.
Custom service types are consumed by Api controllers. Custom Service classes consumes EF database contexts and the generic repository.
My question is: Are HierarchicalLifetimeManager and ContainerControlledLifetimeManager correct lifetime managers for my web api application?
Codes in the UnityConfig class of my application:
using System;
using System.Configuration;
using System.Data.Entity;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using App.Api.Models;
using App.Dal;
public class UnityConfig
{
#region Unity Container
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
#endregion
/// <summary>Registers the type mappings with the Unity container.</summary>
/// <param name="container">The unity container to configure.</param>
/// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to
/// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
public static void RegisterTypes(IUnityContainer container)
{
var connectionStringEntityFramework= ConfigurationManager.ConnectionStrings["AppEntities"].ToString();
// Entity Framework database context and generic repository
// HierarchicalLifetimeManager is used:
container.RegisterType<DbContext, FirstAngularJsEntities>(new HierarchicalLifetimeManager(), new InjectionConstructor(connectionStringFirstAngularJsEntities));
container.RegisterType<IRepository, GenRepository>(new HierarchicalLifetimeManager(), new InjectionConstructor(typeof(DbContext)));
// services
// ContainerControlledLifetimeManager is used:
container.RegisterType<IContactService, ContactService>(new ContainerControlledLifetimeManager());
container.RegisterType<IProductService, ProductService>(new ContainerControlledLifetimeManager());
}
A sample api controller has custom service injected in its constructor:
public class ContactApiController : ApiController
{
private readonly IContactService _contactService;
public ContactApiController(IContactService contactService)
{
_contactService = contactService;
}
...
}
A sample custom service has EF DbContext and repository injected in its constructor:
public class ContactService : IContactService
{
private readonly IRepository _repo;
private readonly DbContext _context;
public ContactService(DbContext context, IRepository repo)
{
_context = context;
_repo = repo;
}
...
}
Using ContainerControlledLifetimeManager you'll get singletons of your services. One instance for a long time (untill IIS recycling).
HierarchicalLifetimeManager is used with child containers - create new instance of object for every child container, so you don't create child containers it works like a singleton again :)
The best way for WebApi apllication is using PerRequestLifetimeManager.
Create new instances for every request to Api.
I tend to look at this as what is the shortest lifetime that is compatible with the semantics of what you are trying to do, with the default lifetime being Transient unless otherwise required.
DbContext holds state so we need to be consistent for the request so PerRequest or Hierachic
Repository is/should be stateless since it's state is the DbContext, so Transient
Services is/should be stateless so Transient
One reason for going with Hierarchic rather than PerRequest is that the PerRequest manager does not play well with Owin, see http://www.reply.com/solidsoft-reply/en/content/managing-object-lifetimes-with-owin-and-unity, and you will need to write some cleanup middleware to replace the HttpModule

ASP.Net Web API Help Page Area returning empty output

I have a preexisting MVC app that I added Web API and Web API Self Documentation using Nuget. While the Web API controllers function fine (return valid responses to HTTP requests) the Help controller is not finding any Web API methods to document.
In the Help controller Index action "Configuration.Services.GetApiExplorer().ApiDescriptions" is returning with 0 results.
What populated ApiDescriptions and are there any config settings I need to set to expose my api to documentations?
The Help Area is a separate area from the rest of my application. Is this causing the piece that finds the Controllers to not find my controllers? Furthermore, I even added a help snipped to the HelpController itself, which still resulted in no API descriptions.
I do also have special routing for my API controllers, so I'm not sure if that's relevant.
After some more searching i found this post which also refers to this post
As mentioned in the first post, Glimpse is the culplit, this workaround solved the issue for me:
<glimpse defaultRuntimePolicy="On" endpointBaseUri="~/Glimpse.axd">
<inspectors>
<ignoredTypes>
<add type="Glimpse.AspNet.Inspector.RoutesInspector, Glimpse.AspNet"/>
</ignoredTypes>
</inspectors>
</glimpse>
This is also a known issue and the workaround is described on this Glimpse GitHub Issue.
I have the same problem and i don't use Glimpse and i solve the problem like this:
In the ProjectName\Areas\HelpPage\Controllers\HelpController.cs file comment the constructors because is not called the implicit constructor public HelpController() : this(GlobalConfiguration.Configuration) default is called the constructor with the parameter public HelpController(HttpConfiguration config) and this initialization of the Configuration property is incorect. And you cand solve this problem like this:
Solution 1:
Comment/Remove the constructors.
public class HelpController : Controller
{
private const string ErrorViewName = "Error";
// public HelpController()
// : this(GlobalConfiguration.Configuration)
// {
// }
// public HelpController(HttpConfiguration config)
// {
// Configuration = config;
// }
/// <summary>
/// GlobalConfiguration By default
/// </summary>
protected static HttpConfiguration Configuration
{
get { return GlobalConfiguration.Configuration; }
}
public ActionResult Index()
{
ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider();
return View(Configuration.Services.GetApiExplorer().ApiDescriptions);
}
....
Solution 2:
inject the default constructor by add this attribute [InjectionConstructor].
public class HelpController : Controller
{
private const string ErrorViewName = "Error";
[InjectionConstructor]
public HelpController()
: this(GlobalConfiguration.Configuration)
{
}
public HelpController(HttpConfiguration config)
{
Configuration = config;
}
/// <summary>
/// GlobalConfiguration By default
/// </summary>
protected static HttpConfiguration Configuration { get; private set; }
....
And problem solved.
I was able to solve this by adding GlobalConfiguration.Configure (WebApiConfig.Register); in my Application_Start () method. Because my application uses OWIN I was registering my APIs only in Startup.Configuration (IAppBuilder app).
After installing HelpPages package from NuGet package manager- Navigate to WebApplication1\Areas\HelpPage\App_Start\HelpPageConfig.cs and uncomment the line below
config.SetDocumentationProvider(new XmlDocumentationProvider(
HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml")));
Also add App_Data/XmlDocument.xml to WebApplication > Properties > Build > Check XML Documentation File

How NOT to use Ninject's Kernel as a resource locator

I am fairly new to Ninject as well and DI in general. I use NHibernate as my ORM for my MVC app and have been quite happy with my results. That is, until I upgraded from Ninject 2.1 to 2.2.
Now, I get errors within my NinjectWebsiteApplication class due to using Ninject’s Kernel as a resource locator.
Example:
void NinjectWebsiteApplication_BeginRequest(object sender, System.EventArgs e)
{
ILogger logger = Kernel.Get<ILogger>();
logger.Debug(“**********REQUEST BEGIN****************”);
logger.Debug(“**** URL = ” + Request.Url.AbsolutePath);
}
Example 2:
protected override void OnApplicationStarted()
{
var bootstrapper = Kernel.Get<Bootstrapper>();
bootstrapper.RegisterAllAreas();
AreaRegistration.RegisterAllAreas();
......
(More stuff here, like AutoMapper mappings, etc.)
......
}
*The Bootstrapper class is a class I created where I register my routes, global filters, etc.
In both of the above examples, I receive a warning about the Kernel.Get() functions that states the following:
'Ninject.Web.Mvc.NinjectHttpApplication.Kernel' is obsolete: "Do not use Ninject as Service Locator"
After conducting several searches on this, the general consensus is that this is true.
I am trying to work around this, but am at a bit of a loss as to what to do.
I loaded the newest Ninject.Web.Mvc NuGet package which creates the NinjectMVC3 static class under the App_Start folder. I see that they're referencing Microsoft.Web.Infrastructure.DynamicModuleHelper, but I don't see where that fits in to what I'm trying to do.
If anyone has any hints that will help me fix my little mess, I would greatly appreciate it!
The way to deal with the first is not to use the NinjectWebsiteApplication_BeginRequest event but to write a custom global action filter:
public class LogActionFilterAttribute : ActionFilterAttribute
{
private readonly ILogger _logger;
public LogActionFilterAttribute(ILogger logger)
{
_logger = logger;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
_logger.Debug("**********REQUEST BEGIN****************");
_logger.Debug("**** URL = " + filterContext.HttpContext.Request.Url.AbsolutePath);
}
}
and then in your App_Start/NinjectMVC3.cs:
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ILogger>().To<Logger>();
kernel.BindFilter<LogActionFilterAttribute>(FilterScope.Global, 1);
}
Don't forget to add using Ninject.Web.Mvc.FilterBindingSyntax; in order to bring the BindFilter<> extension method into scope.
And since you have access to the kernel inside the RegisterServices method which happens at application startup you could wire up everything else including your bootstrapper, ...
As far as your Global.asax is concerned you no longer use any Ninject specific stuff in it. You should not derive from NinjectApplication.
The WebActivator infrastructure allows you to have a separate initialization method.

ASP.Net MVC 3 project with Ninject and HierarchicalLifetimeManager?

First of all, dependency injection is relatively new to me. I did a first project using Unity.MVC3, and now I would like to switch to Ninject on a new project, since it seems to be the most popular dependency injector for .Net projects. So now, I am trying to use Ninject v2.2.1.4 with Ninject.MVC3 v2.2.2.0 in my project.
In my previous project where I was using Unity, I had something like the following code in my Bootstrapper class:
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
container.RegisterType<ITestService, TestService>();
container.RegisterType<IDatabaseFactory, DatabaseFactory>(new HierarchicalLifetimeManager());
container.RegisterType<IUnitOfWork, UnitOfWork>();
container.RegisterType<ILoggingService, LoggingService>();
container.RegisterControllers();
return container;
}
Now, I my new project, I replaced this with something like the following code in the NinjectMVC3 class (App_Start):
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ITestService>().To<TestService>();
//This does not compile:
//kernel.Bind<IDatabaseFactory>().To<DatabaseFactory>(new HierarchicalLifetimeManager());
kernel.Bind<IDatabaseFactory>().To<DatabaseFactory>();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
kernel.Bind<ILoggingService>().To<LoggingService>();
}
However, I don't know what I should do with the DatabaseFactory binding, since it normally requires the use of HierarchicalLifetimeManager. Can anyone tell me how to properly create the binding for DatabaseFactory?
First of all, add these references bu NuGet to be sure that you have a compatible set of packages.
Then, if you add the Ninject.Web.MVC it will setup the project initialization code for you through a power shell script.
And last make a BindModule class like this and add it to module in CreateKernel method that have been created in second step.
public class BindModule : NinjectModule
{
public override void Load()
{
this.Bind<IControllerActivator>().To<CustomControllerActivator>().InRequestScope();
this.Bind<MembaseClient>().ToMethod(context => new MembaseClient()).InSingletonScope();
this.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
this.Bind<ISessionFactory>().ToMethod(o => MyAutoMapper.sessionFactory).InSingletonScope();
this.Bind<ISession>().ToMethod(o => MyAutoMapper.sessionFactory.OpenSession()).InRequestScope();
}
}
Part of NinjectMVC3 class
public static class NinjectMVC3
{
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var modules = new NinjectModule[] { new BindModule() };
var kernel = new StandardKernel(modules);
RegisterServices(kernel);
return kernel;
}
}
As you can see above Ninjet has built in functions to take care of different life cycles for each object.

Getting SNAP(AOP), NInject and ASP.Net MVC 3 working together

Has anyone got the SNAP AOP framework working with MVC 3 and Ninject.
The samples given when adding Snap using NuGet to an MVC 3 project don't specifcally work well with a previously added NInject package. I have tried to get it working based on the normal NInject approach but just cannot get it to actually intercept!
Can anyone show how to do this in code please?
I figured it out with the latest version of Ninject through NuGet which now adds a class call NinjectMVC3 in a new AppStart folder in the MVC3 application.
The code I used is as folows:
In the automatically created NinjectMVC3.cs CreateKernel() method:-
private static IKernel CreateKernel()
{
// Wire it up with AOP
NinjectAopConfiguration.NinjectAopConfigure();
//var kernel = new StandardKernel(); // Removed
RegisterServices(NinjectAopConfiguration._container.Kernel);
return NinjectAopConfiguration._container.Kernel;
}
I also wired up Ninject for the various injection targets in RegisterServices() method.
Next I took the sample code generated by NuGet when adding SNAP.Ninject to the MVC 3 application, renamed it NinjectAOP.cs and made it look like this:
public static class NinjectAopConfiguration
{
public readonly static NinjectAspectContainer _container;
static NinjectAopConfiguration()
{
_container = new NinjectAspectContainer();
}
public static void NinjectAopConfigure()
{
SnapConfiguration.For(_container).Configure(c =>
{
c.IncludeNamespace("MyNamespace.Model.*");
c.Bind<ExceptionLoggingInterceptor>().To<ExceptionLoggingAttribute>();
});
}
}
I also needed to do an assembly binding redirect for Ninject as follows because there is an assembly version conflict somewhere for Ninject:
I hope this helps someone.
I invite anyone to have a look and see if they can improve this please.

Resources