Injection question when using Ninject 2 in ASP.NET MVC application - asp.net-mvc

I'm using Ninject 2 with an ASP.NET MVC web app. All the dependencies are handled properly down the stack (Controllers->Services->Repositories). However I have some classes in the Services project that aren't in that "chain" that I also want to inject when the app starts. How do I get Ninject to recognize them? I have public properties with [Inject] attributes but when the app runs, they're null. What am I missing?
Here is my MvcApplication class:
public class MvcApplication : NinjectHttpApplication
{
protected override void OnApplicationStarted() {
RegisterRoutes(RouteTable.Routes);
RegisterAllControllersIn(Assembly.GetExecutingAssembly());
}
protected override IKernel CreateKernel() {
var modules = new INinjectModule[] {
new Services.ServiceModule(),
new Data.DataModule()
};
var kernel = new StandardKernel(modules);
return kernel;
}
// route registration removed
}
I double checked both modules to make sure that the correct bindings exist.
Sample from a module:
public class ServiceModule : NinjectModule
{
public override void Load() {
Bind<IAccountService>().To<AccountService>();
....
}
}

In order for Ninject to inject dependencies, you have to create the object using the kernel. That's easy for objects in the natural dependency chain (ie. in your app, Controllers->Services->Repositories), but can be tricky for those outside of it.
You have to either add the additional types as dependencies of one of the types that is created in the natural chain, or somehow get a hook on the kernel and call Get<T>. To do that, you might have to use a static service locator.

Are you overriding CreateKernel()? You need to do that and do your binding in there.

Related

Inject ILogger into Application_Error in ASP.NET MVC 5 project using Owin [duplicate]

How do I inject dependencies into the global.asax.cs, i.e. the MvcApplication class?
Having previously used the Service Locator (anti-)pattern for dependency injection, I am trying to follow best practice advice in my latest MVC application by using an IOC container (specifically Unity.Mvc3 because it comes with an implementation of the IDependencyResolver out of the box) and constructor injection.
Everything seems quite straight forward so far except for a couple of snags, one of which is in the global.asax.cs (the other is for custom attributes but there's aleady a question on SO covering that).
The HttpApplication event handlers in the MvcApplication class such as:
Application_Start()
Application_EndRequest(object sender, EventArgs e)
Application_AcquireRequestState(object sender, EventArgs e)
may require external dependencies, e.g. a dependency on an ILogService. So how do I inject them without resorting to the service locator (anti-)pattern of e.g.
private static ILogService LogService
{
get
{
return DependencyResolver.Current.GetService<ILogService>();
}
}
Any help/advice greatly appreciated!
The class in your global.asax.cs is your Composition Root, so you can't (and shouldn't) inject anything into it from the outside.
However, there's only one instance of the MvcApplication class, so if you need a service in one of its methods, you can just declare it as a member field - e.g:
public class MvcApplication : System.Web.HttpApplication
{
private readonly ILogService log;
public MvcApplication()
{
this.log = new MyLogService();
}
protected void Application_Start()
{
// ...
this.log.Log("Application started");
}
}
You must use AutofacConfig.Resolve<T>() instead using DependencyResolver.Current.GetService<T>() to get your services without errors.

SignalR 2 Dependency Injection with Ninject

I have an existing MVC application that is using Dependency Injection with Ninject. I installed the Ninject.MVC3 nuget package and it creates a class called NinjectWebCommon in my App_Start, which completely isolates the kernel and registers all of my bindings:
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
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;
}
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IFoo>().To<Foo>();
}
We have a new requirement that we thought SignalR would be able to satisfy, so we installed SignalR 2 nuget package into the project. I created a Hub and did some searching on how to implement Dependency Injection into the project and found an article that suggests creating a SignalRDependencyResolver. http://www.asp.net/signalr/overview/signalr-20/extensibility/dependency-injection
The article has you creating a kernel in the Startup.cs file that is used for registering SignalR in OWIN:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var kernel = new StandardKernel();
var resolver = new NinjectSignalRDependencyResolver(kernel);
kernel.Bind<IStockTicker>()
.To<Microsoft.AspNet.SignalR.StockTicker.StockTicker>() // Bind to StockTicker.
.InSingletonScope(); // Make it a singleton object.
kernel.Bind<IHubConnectionContext>().ToMethod(context =>
resolver.Resolve<IConnectionManager>().GetHubContext<StockTickerHub>().Clients
).WhenInjectedInto<IStockTicker>();
var config = new HubConfiguration()
{
Resolver = resolver
};
app.MapSignalR(config);
}
}
The problem is that this approach has me creating two different kernels and they seem to have their own set of dependencies that they know how to resolve. If I have a dependency defined in NinjectWebCommon, the Hub doesn't know how to resolve that dependency. Without exposing my kernel in NinjectWebCommon, what is the proper way to add DI into SignalR using the Ninject.MVC3 package?
None of the current answers directly answer your question. Also achieving the result you are after is very straightforward once you know exactly what to do. The "proper" way to do this is to set SignalR's dependency resolver in the CreateKernel method of the NinjectWebCommon class.
Assuming you have created a NinjectSignalRDependencyResolver class as you mention, no other code needs to be added anywhere except for the line highlighted in the code snippet below:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
// THIS LINE DOES IT!!! Set our Ninject-based SignalRDependencyResolver as the SignalR resolver
GlobalHost.DependencyResolver = new NinjectSignalRDependencyResolver(kernel);
RegisterServices(kernel);
return kernel;
}
Apart from the above, nothing more needs to be done except declaring your bindings in the RegisterServices method of NinjectWebCommon. In your example this would look like:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IStockTicker>()
.To<Microsoft.AspNet.SignalR.StockTicker.StockTicker>() // Bind to StockTicker.
.InSingletonScope(); // Make it a singleton object.
kernel.Bind<IHubConnectionContext>().ToMethod(context =>
resolver.Resolve<IConnectionManager>().GetHubContext<StockTickerHub>().Clients
).WhenInjectedInto<IStockTicker>();
}
Except for the NinjectSignalRDependencyResolver class you created, no other code needs to be added. Importanly, the OwinStartup class remains unmodified, as follows:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
The above example achieves the following important outcomes which were what you asked in your question:
You only have a single Ninject Kernel created
The kernel and all binding configurations remain confined to NinjectWebCommon
The default SignalR resolver is your NinjectSignalRDependencyResolver
Dependency Injection into all SignalR hubs is achieved
Hopefully this helps people out.
Have you tried adding the StockTickerHub itself to your kernel?
By default, SignalR uses Activator.CreateInstance to construct Hubs without any constructor arguments. If you want to inject your own dependencies into a Hub, you can do so by registering the Hub with SignalR's dependency resolver.
https://github.com/SignalR/SignalR/blob/2.0.1/src/Microsoft.AspNet.SignalR.Core/Hubs/DefaultHubActivator.cs#L28
If you want to get really creative, you can register your own IHubActivator instead of registering all of Hubs individually.
I go into more detail in how Hubs are created by default in this answer: SignalR with IoC (Castle Windsor) - which lifetime for hubs?
There is a problem with the singleton scope. I donĀ“t know who should get the blame here (Ninject, SignalR, MVC, etc...), but it works if you use ToConstant:
var binding = Bind<IMustBeSingleton>().ToConstant(new MustBeSingleton());
I had the same problem, and I found the solution: SignalR, WebAPI and MVC sharing the same dependency resolver kernel
I shared a complete solution with MVC, WebAPI and SignalR using the same Ninject kernel: https://drive.google.com/file/d/0B52OsuSSsroNX0I5aWFFb1VrRm8/edit?usp=sharing
That example web app, contains a single page that shows the AppDomain and GetHashCode of an object that is supposed to be unique across the three frameworks, giving a result similar to:
Dependency Test
Framework IMySingletonService instance
MVC AppDomainId:2 / HashCode:5109846
WebAPI AppDomainId:2 / HashCode:5109846
SignalR AppDomainId:2 / HashCode:5109846
I hope this helps.

Autofac, MVC (with ActionFilters), Web.Forms - dependency resolution conflict

I've got a legacy Web.Forms app that been partially rewritten to MVC. MVC part uses autofac as a dependency injection container.
MVC part have custom filter defined:
public class CustomActionFilter : ActionFilterAttribute
{
protected ILogger Logger { get; set; }
public CustomActionFilter(ILogger logger) { Logger = logger; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Logger.Log("OnActionExecuting");
}
}
It works fine when Web.Forms integration is disabled in web.config. Hovewer, when I try to use Web.Forms autofac integration, I've got the NullReferenceException related to AutofacFilterProvider somewhere in autofac internals (stack trace).
Global.asax.cs: http://pastebin.com/437Tnp0t
web.config: http://pastebin.com/5pU6SH6c
Note that CustomActionFilter is registered as global filter, thus it is registered with autofac:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(DependencyResolver.Current.GetService<CustomActionFilter>());
}
}
I've tried:
using separate containers for MVC and Web.Forms - same result
Use property injection instead of constructor - same result
Explicitly trigger dependencies resolution on web.forms pages (like this) - worked
So, the question is, are there any way to provide behind-the-scenes dependency resolution both to MVC and web.forms part. I'm new to autofac and somewhat new to dependency injection containers in general, so I might just miss something obvious.
Update: error has nothing to do with custom filters. If I remove all references to custom filters the bug behavior still the same, even the stack trace.
Actually there are two bugs? in Autofac which causing this behavior:
Bug #1: As side effect of the fix of Issue 351 the AutofacDependencyResolver needs to registered in the created Request bound LifeTimeScopes. The MVC intergration does this but the Winforms integration of course does not.
Bug? #2: Both the RequestLifetimeScopeProvider and the ContainerProvider stores the created ILifetimeScope with the same key HttpContext.Current.Items:
static ILifetimeScope LifetimeScope
{
get { return (ILifetimeScope)HttpContext.Current.Items[typeof(ILifetimeScope)]; }
set { HttpContext.Current.Items[typeof(ILifetimeScope)] = value; }
}
So there is a little bit race condition here because depending on which module gets executed first the WebForms or the MVC intergartion ILifetimeScope wins. So if the WebForms module wins the AutofacDependencyResolver won't be registered and you get the nice non descriptive exception.
Fix/workaround:
But there is an simple workaround: you just need to register the AutofacDependencyResolver in the ContainerProvider requestLifetimeConfiguration so no matter which one wins (WebForm vs. MVC) the AutofacDependencyResolver will be always registered:
var autofacDependencyResolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(autofacDependencyResolver);
_containerProvider = new ContainerProvider(container, requestContainerBuilder =>
requestContainerBuilder.RegisterInstance(autofacDependencyResolver)
.As<AutofacDependencyResolver>());

Do I need to use ninject.mvc extension anymore?

I see there is an extension for Ninject integration with asp.net-mvc but it looks like I can integrate Ninject with mvc fine without this extension. For example:
public class NinjectDependencyResolver : IDependencyResolver
{
private readonly IResolutionRoot _resolutionRoot;
public NinjectDependencyResolver(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
public object GetService(Type serviceType)
{
return _resolutionRoot.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _resolutionRoot.GetAll(serviceType);
}
}
public class MvcApplication : HttpApplication
{
void Application_Start()
{
var modules = new INinjectModule[] { new ServiceModule() };
var kernel = new StandardKernel(modules);
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
Is this some legacy extension or is it still relevant? I see recent updates to the source code so I was a bit confused
You can implement your own Dependency Resolver. So yes you dont need it. You can integrate Ninject quite easily without the extension. But the question is why should you do this? The Ninject.MVC3 extension provides everything to add support for Ninject without having to implement an own Dependency Resolver. This has several advantages:
Unlike the implementation you are proposing, the implementation of this extension is correct and proved to work in many applications.
It is mantained together with Ninject core. In case Ninject core changes all the necessary changes will be done for you. E.g. Ninject 3.0.0 core does not have InRequestScope anymore, but with Ninject.MVC3 you still have this scope.
This extension is much more than a Dependency Resolver. Read the documentation!
It runs side aside with other web technologies and the configuration can be shared. E.g. MVC4 Web API, WCF, WebForms

ASP.NET MVC, MVCContrib, Structuremap, getting it working as the controllerfactory?

I'm trying to get structuremap to correctly create my controllers, I'm using DI to inject an INewsService into a NewsController and thats the only constructor I have.
public class NewsController : Controller
{
private readonly INewsService newsService;
public NewsController(INewsService newsService)
{
this.newsService = newsService;
}
public ActionResult List()
{
var newsArticles = newsService.GetNews();
return View(newsArticles);
}
}
and I'm using this code to start the app
public class Application : HttpApplication
{
protected void Application_Start()
{
RegisterIoC();
RegisterViewEngine(ViewEngines.Engines);
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterIoC()
{
ObjectFactory.Initialize(config => {
config.UseDefaultStructureMapConfigFile = false;
config.AddRegistry<PersistenceRegistry>();
config.AddRegistry<DomainRegistry>();
config.AddRegistry<ControllerRegistry>();
});
DependencyResolver.InitializeWith(new StructureMapDependencyResolver());
ControllerBuilder.Current.SetControllerFactory(typeof(IoCControllerFactory));
}
}
But Structuremap doesn't seem to want to inject the INewsService and I get the error
No parameterless constructor defined for this object.
What have I missed?
I use the "Default Conventions" mechanism that StructureMap provides to avoid needing to individually configure each interface. Below is the code I use to make that work:
My Global.asax has this line in Application_Start (which uses the StructureMap factory from MvcContrib):
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ObjectFactory.Initialize(x =>
{
x.AddRegistry(new RepositoryRegistry());
});
ControllerBuilder.Current.SetControllerFactory(typeof(StructureMapControllerFactory));
}
And the RepositoryRegistry class looks like this:
public class RepositoryRegistry : Registry
{
public RepositoryRegistry()
{
Scan(x =>
{
x.Assembly("MyAssemblyName");
x.With<DefaultConventionScanner>();
});
}
}
The DefaultConventionScanner looks for pairs of Interfaces/Classes that follow the nameing convention of ISomethingOrOther and SomethingOrOther and automatically associates the latter as a concrete type for the former interface.
If you didn't want to use that default convention mechanism, then you would add code in the Registry class to explicity map each of your interfaces to the concrete types with this syntax:
ForRequestedType<ISomethingOrOther>().TheDefaultIsConcreteType<SomethingOrOther>();
Unless I'm missing something, you are not telling StructureMap what concrete type to use for INewsService. You need to add something like:
TheConcreteTypeOf<INewsService>.Is<MyConcreteNewsService>();
I don't know the exact syntax off the top of my head, but that's what you're missing. Once you specify that then it will know what instance of the INewsService to inject into the controller.
ASP.NET MVC currently instantiates controllers using the default parameterless constructor, which precludes any constructor-based dependency injection. To do that, you really need to use the MvcContrib project, which has built-in support for StructureMap (and Castle/Spring.NET/Unity), although the current documentation is non-existent (literally, you get a stub wiki page, not a good sign). Erv Walter's code sample in this thread shows how to set up the StructureMap integration.

Resources