ASP.NET Web API (Self Host) + Ninject - Default Bindings - ninject-2

I'm converting a project from WCF Web API to ASP.NET Web API - thanks MS :(
Self Hosting POC code:
static void Main(string[] args)
{
var kernel = new StandardKernel();
const string baseAddress = "http://localhost:8080";
var config = new HttpSelfHostConfiguration(baseAddress);
config.ServiceResolver.SetResolver(new NinjectServiceLocator(kernel));
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new {id = RouteParameter.Optional});
var server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
Console.WriteLine("The server is running....");
Console.ReadLine();
}
I'm registering Ninject as the dependency resolver. To accomplish this, I am using the CommonServiceLocator.NinjectAdapter to register it:
config.ServiceResolver.SetResolver(new NinjectServiceLocator(kernel));
This seems to work as far as I can tell although it feels a little dirty using SetResolver(object).
The problem I have now is when I try to run it there are a lot of bindings that are no longer registered (i.e. IHttpContollerFactory, ILogger, etc.).
Do I have to go through one-by-one and re-register all of the "default" dependencies? It seems odd that defaults are registered with the default dependency resolver but I can't see a quick way to re-register the defaults when a new dependency resolver is set. For something like the ILogger, I can't even seem to gain access to the default System.Web.Http.Common.Logging.DiagnosticLogger to make the binding.
Am I missing something?

You don't have to re-register the default services. If you return null the framework will default back to it's internal DI container. Also, in the latest bits it will only ask once.

In the end it is probably better just to create a IDependencyResolver for Ninject. I'm sure there will be a "proper" one created by someone whom has greater knowledge of Ninject but for now I'm using:
public class NinjectDependencyResolverAdapter : IDependencyResolver
{
private readonly IKernel kernel;
public NinjectDependencyResolverAdapter(IKernel kernel)
{
this.kernel = kernel;
}
#region Implementation of IDependencyResolver
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
#endregion
}

Related

ASP.Net MVC 5 + SignalR + Ninject

What is the best practice way for to wire up Ninject with both MVC5 and SignalR?
Ninject recommends having Global.asax inherit NinjectHttpApplication and implementing a CreateKernal method:
//Global.asax ([Ninject MVC Website Guidance][1])
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel(new NinjectRegistrations());
var ninjectResolver = new CustomNinjectDependencyResolver(kernel);
DependencyResolver.SetResolver(ninjectResolver); // MVC
GlobalConfiguration.Configuration.DependencyResolver = ninjectResolver; // Web API
return kernel;
}
SignalR would like us to use their OwinStartup class register a NinjectDependencyResolver:
//OWIN Startup ([ASP.Net Website Guidance][2])
public void Configuration(IAppBuilder app)
{
var kernel = new StandardKernel();
var resolver = new NinjectSignalRDependencyResolver(kernel);
var config = new HubConfiguration();
config.Resolver = resolver;
Microsoft.AspNet.SignalR.StockTicker.Startup.ConfigureSignalR(app, config);
}
IKernel and NinjectDependencyResolver are needed in both these locations. One option is to start using Static singletons for these, but this does not seem in the spirit of the loose coupling we are shooting for by using Ninject in the first place.
Thanks for any pointers!
You only need to call MapSignalR from Owin configuration. The Ninject MVC pipeline uses WebActivator to activate Ninject, install package Ninject.MVC5.
Look here how to add SignalR to Ninject startup
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/blob/master/SignalR.EventAggregatorProxy.Demo.MVC4/App_Start/NinjectWebCommon.cs#L45

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.

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

MVC3 tool using Entity Framework caching issues with Ninject

I've got a new MVC 3 application which is showing some issues when modifying data manually in the Database.
The tool is still in development and once in a while I want to change my user's teamId. When I do so, I have to kill the Web development Server and run it again otherwise the queries don't pick the new teamId.
Same thing when I publish the tool to IIS, if I ever modify something on the database, I need to either copy over the 'bin' folder again or stop the application and re-run it.
When I modify data from the application itself, I have no problems.
This is how my Ninject looks like:
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel kernel = new StandardKernel(new TrackerServices());
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
return null;
return (IController)kernel.Get(controllerType);
}
private class TrackerServices : NinjectModule
{
public override void Load()
{
var context = new TrackerEntities();
Bind<IUserRepository>().To<UserRepository>().WithConstructorArgument("context", context);
}
}
}
My Interface:
public interface IUserRepository : IRepository<User>
{
User GetByName(string name);
}
my Implementation:
public User GetByName(string login)
{
var userLogin = _misc.GetUsername(login);
return _context.Users.Where(x => x.Login == userLogin).Single();
}
And my Index Action
public ActionResult Index()
{
var teamid = (int)_users.GetByName("myName").TeamId;
This has never happened before, but this tool is the first one I'm using with Ninject. I'm wondering if there's a relation between my problem and using a repository?
There are two issues that are combining to create this problem:
The way you've created your context is causing it to effectively be a singleton.
Entity Framework will not automatically check for a new version of an entity which the context is already tracking.
To solve this, I would recommend that you recreate your repository once per request (there won't be a significant performance hit for this, as it's fairly lightweight), by using this binding:
Bind<IUserRepository>().To<UserRepository>().InRequestScope();
Ninject should be able to create your TrackerEntities context automatically, but if not (or if you want to make it clear), you can use the following binding:
Bind<TrackerEntities>().ToSelf().InRequestScope(); (The InRequestScope is not really required here, as the default transient scope should be okay).
You could also go down the road of forcing a refresh of the entity (using ObjectContext.Refresh()), but that's probably not a great idea because you'd have to do it explicitly for each entity.

Injection question when using Ninject 2 in ASP.NET MVC application

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.

Resources