I have a new MVC3 application with a few legacy Web Form pages. I'm familiar with with Ninject and MVC but I want to use Ninject with the Web Form pages as well. I've hacked something together but I'm not sure if it's the right way to go about this.
I've exposed the Ninject kernel as follows:
public static IKernel Kernel { get { return CreateKernel(); } }
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
RegisterServices(kernel);
return kernel;
}
I then created a base class for my Web Form pages that injects the kernel:
public class NinjectBase : Page
{
public IKernel Kernel { get; private set; }
public NinjectBase() { Kernel = NinjectMVC3.Kernel; }
public void Page_Init() { Kernel.Inject(this); }
}
This seems to work well enough. Is there anything wrong with this approach? Is there another way I should be going about this?
Ninject 2.4 will support all the web technologies (ASP.NET, MVC, WCF) side a side.
If you are not yet on production go and get 2.3.0.x
the source from Github: https://github.com/ninject
or binaries from the Continuous Integration Server at http://teamcity.codebetter.com
You will need Ninject, Ninject.Web, Ninject.Web.Common, Nnject.Web.MVC3
Related
Entity Framework 4, Ninject 3, MVC3
Currently in my web app i have been using a rather rudimentary approach to per request instantiation of an Object Context. So I am experimenting with Ninject, and some old sample code, but I am unsure how to proceed with the following..
Effectively I want to be able in the controller to do the equivalent of: DB_Entities.Current.Albums ... Should i be instantiating a StandardKernel every time?
The sample i was looking at was using the following: MvcApplication.Container.Get(); but in Ninject 3 with the App_Start hookup I dont have access to Container..
My attempt to replicate the above line, is failing at runtime.
using MusicStoreEntities;
using Ninject;
using TestMVC3WithIOC.App_Start;
using System.Data.Objects;
namespace TestMVC3WithIOC.Models
{
public partial class MusicStoreEntities
{
public static MusicStoreEntities Current
{
get
{
using (IKernel kernel = new StandardKernel())
{
return (MusicStoreEntities)kernel.Get<ObjectContext>();
}
}
}
}
}
Also, note, that in App_Start\NinjectWebCommon.cs I have the following modification:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ILogger>().To<NLogger>();
kernel.Bind<ObjectContext>().To<MusicStoreEntities>().InRequestScope();
}
Although a workable solution, it seems ill-advised to pass the entire Kernel into a class, because it tends to obscure the classes actual, specific dependencies. A better approach is to pass a factory dependency into your controller's constructor.
public partial class MusicStoreEntities
{
private readonly IEntitiesFactory _factory;
public MusicStoreEntities(IEntitiesFactory factory)
{
_factory = factory;
}
}
IEntitiesFactory has a simple implementation with a single method GetObjectContext().
(I believe also the "Unit of Work" pattern is popular at the moment, but I can't really speak to that as I haven't used it. Maybe worth looking into.)
I have an MVC3 project that I am using Ninject to inject an Entity Framework context into. I am using the Ninject package (3.0.0.15), Ninject.MVC3 (3.0.0.6), and Ninject.Web.Common (3.0.0.7). Everything is working really great, except when I try to inject into a WebForms code behind file. I am assuming that this is because I don't have something wired in correctly, but am not sure at how to wire it in. Ninject is also not working in files that Razor instantiates.
Here is my code for my Code Behind:
[Inject]
public IDbContext DataContext { get; set; }
The Context property comes out null every time. It worked just fine until I updated to Ninject 3.0.
My start method is as follows:
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
Bootstrapper.Initialize(CreateKernel);
}
Any ideas on how to make Ninject inject the DataContext into the WebForm and into classes instantiated by Razor?
For this to work you need to install the Ninject.Web NuGet (the latest version at the time of this writing is 3.0.0.5) and then have your webform derive from Ninject.Web.PageBase instead of System.Web.UI.Page:
public partial class WebForm1 : Ninject.Web.PageBase
{
[Inject]
public IDbContext Ctx { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
}
}
Also notice that I used Ctx as property name because there's already a property called Context on the System.Web.UI.Page class that you are hiding (you should have gotten a compile time warning).
I want to use RavenDB with ninject in my asp.net mvc3 project, Any idea how I have to configure this?
kernel.Bind<Raven.Client.IDocumentSession>()
.To<Raven.Client.Document.DocumentStore>()
.InSingletonScope()
.WithConstructorArgument("ConnectionString", ConfigurationManager.ConnectionStrings["RavenDB"].ConnectionString);
Here's how I do mine:
If you install Ninject with Nuget, you'll get an /App_start/ NinjectMVC3.cs file. In there:
private static void RegisterServices(IKernel kernel)
{
kernel.Load<RavenModule>();
}
Here's the RavenModule class:
public class RavenModule : NinjectModule
{
public override void Load()
{
Bind<IDocumentStore>()
.ToMethod(InitDocStore)
.InSingletonScope();
Bind<IDocumentSession>()
.ToMethod(c => c.Kernel.Get<IDocumentStore>().OpenSession())
.InRequestScope();
}
private IDocumentStore InitDocStore(IContext context)
{
DocumentStore ds = new DocumentStore { ConnectionStringName = "Raven" };
RavenProfiler.InitializeFor(ds);
// also good to setup the glimpse plugin here
ds.Initialize();
RavenIndexes.CreateIndexes(ds);
return ds;
}
}
And for completeness here's my index creation class:
public static class RavenIndexes
{
public static void CreateIndexes(IDocumentStore docStore)
{
IndexCreation.CreateIndexes(typeof(RavenIndexes).Assembly, docStore);
}
public class SearchIndex : AbstractMultiMapIndexCreationTask<SearchIndex.Result>
{
// implementation omitted
}
}
I hope this helps!
I recommend using a custom Ninject Provider to set up your RavenDB DocumentStore. First place this in your code block that registers your Ninject services.
kernel.Bind<IDocumentStore>().ToProvider<RavenDocumentStoreProvider>().InSingletonScope();
Next, add this class that implements the Ninject Provider.
public class RavenDocumentStoreProvider : Provider<IDocumentStore>
{
var store = new DocumentStore { ConnectionName = "RavenDB" };
store.Conventions.IdentityPartsSeparator = "-"; // Nice for using IDs in routing
store.Initialize();
return store;
}
The IDocumentStore needs to be a singleton, but do not make the IDocumentSession a singleton. I recommend that you simply create a new IDocumentSession using OpenSession() on the IDocumentStore instance Ninject gives you whenever you need to interact with RavenDB. IDocumentSession objects are very lightweight, follow the unit-of-work pattern, are not thread-safe, and are meant to be used and quickly disposed where needed.
As others have done, you might also consider implementing a base MVC controller that overrides the OnActionExecuting and OnActionExecuted methods to open a session and save changes, respectively.
Can somebody shine a little light for me?
I've got my website all running using Windsor Castle. I have a controller factory and installers for controllers and services. All nice.
Now I've just created a IDependencyResolver implementing class called WindsorDependencyResolver with a straigh-forward implementation:
public class WindsorDependencyResolver : System.Web.Mvc.IDependencyResolver
{
private readonly IKernel _kernel;
public WindsorDependencyResolver (IKernel kernel)
{
_kernel = kernel;
}
public object GetService(Type serviceType)
{
return _kernel.Resolve(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _kernel.ResolveAll(serviceType) as IEnumerable<object>;
}
}
I've got it setup like so (global.asax):
DependencyResolver.SetResolver(new WindsorDependencyResolver(kernel));
And now what? When is this 'used'? Should I stop using kernel.Resolve(someType)?
My understanding is the IDependencyResolver is what is used internally by MVC 3 to do Service Location/Inversion of Control. So in order for your Controllers to get instantiated properly, and be able to inject whatever dependencies you have, you need to tell MVC how to talk to the container your using (Windsor in your case).
You would still want to use kernel.Resolve(someType) when you need to get something out of the container that is not injected for you via constructor/property injection.
Interestingly, the MSDN documentation points to Brad Wilson's Blog Post on the IDependencyResolver for details.
It sounds like you already have a custom IControllerFactory. If so, just stick with it. It's a much better solution than the hack that is IDependencyResolver (which has lots of problems).
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.