How can you inject objects into non-controller objects using Ninject 3.0 with ASP.NET MVC3 - asp.net-mvc-3

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).

Related

How to run a method at the beginning of an MVC3 project?

I need to populate an element from the Database, first thing when I compile/run my MVC3 application.
I have a static class and static method to populate the element. I just need to know how I could somehow call the method at the startup of my application.
Here's the code:
public static class Select_Brands
{
public static IQueryable<Brand> BrandsQ { get; set; }
public static IQueryable<Brand> GetBrands()
{
using (Online_Store_DBEntities EFModel = new Online_Store_DBEntities())
{
BrandsQ = EFModel.Brands;
}
return BrandsQ;
}
}
Is there any way ?
In every MVC Application you have a Global.asax like in an ASP.NET Application and you can run code in Application_Start() Method.
But you should think about where to persist the data and what you really use this for.
There is a method in the global.asax file called Application_Start - sounds like this could be a candidate for what you want.

What is the best way to create EF DbContext instance for ASP.NET MVC

In order to support lazy loading feature in EF, what is the best way to instantiate DbContext?
I know HttpContext's current item is good place to create DbContext via Application_BeginRequest method and Application_EndRequest method, but in some sample codes of MSDN and official asp.net mvc site, they just create DbContext in Controller's constructor and dispose it in controller's Dispose() method.
I think the both ways are not too different because all of those all implement session per request pattern.
I just want to make sure that my understanding is correct or not.
The Dispose() method in the controller isn't always reliable. By the same token, Session is probably not a good idea either. "Best" is probably subjective, but we've had the best success by using dependency injection (Castle Windsor) and following a Unit of Work Repository pattern.
Setup the unit of work along the following lines:
public class UnitOfWork : IUnitOfWork
{
public UnitOfWork()
{
this.Context = new MyEFEntities();
this.Context.ContextOptions.LazyLoadingEnabled = true;
}
public void Dispose()
{
this.Context.Dispose();
}
public ObjectContext Context { get; internal set; }
}
Setup your repository:
public class Repository<TEntity> : IRepository<TEntity>
where TEntity : class
{
public Repository(IUnitOfWork unitOfWork)
{
Context = unitOfWork.Context;
ObjectSet = Context.CreateObjectSet<TEntity>();
}
public ObjectContext Context { get; set; }
public IObjectSet<TEntity> ObjectSet { get; set; }
}
Register with Castle in Global.asax:
void Application_Start()
{
this.Container.Register(
Component.For<IUnitOfWork>()
.UsingFactoryMethod(() => new UnitOfWork())
.LifeStyle
.Is(LifestyleType.PerWebRequest)
);
ControllerBuilder.Current.SetControllerFactory(
new WindsorControllerFactory(this.Container));
}
And use in your controller (or wherever you're using it, as long as it's injectable):
public class SomeController
{
public SomeController(IRepository<MyEntity> repository)
{
this.Repository = repository;
}
public IRepository<MyEntity> Repository { get; set; }
public ActionResult MyAction()
{
ViewData.Model = this.Repository.ObjectSet.Single(x => x.Condition); //or something...
}
}
Any lazy loading here could potentially be a trap for a future issue. Without DI, without a repository - its hard to see anything working without it being a hack for lazy loading. Also do you you plan on passing your entities to your view. If so this is going to create a bad overlap. The controller should package data for your view, not have things evaluated later in your view.
For MVC best practices, you should flatten out your domain model as much as possible into a viewmodel (if flattening makes sense) and use the view model. Since you would ideally then know what would be lazy loaded, it may make more sense to take the hit up front and use .Include() in your query to eager load, otherwise you can issue many many queries to the database.
I've used a session factory pattern and saved the DBContext in the session object. It will stay open per session. I haven't had problems with it so far.

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.

How to inject dependencies into the global.asax.cs

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.

Ninject into a Webactivator invoked class

I use the nuget template way of ninjectning my MVC3 app,
which means I have use WebActivator to invoke a method on a static class that in turn creates a Ninject bootstrapper and hooks up to MVC3.
That works fine for Controller, adapters etc. But I want to have another Webactivator activated class which gets its dependencies using Ninject.
I got it to work with a poor mans solution, but I would prefer a more elegant solution.
First I make sure my Webactivator class uses the PostApplicationStartMethod invoke, since the Ninject module uses the PreApplicationStartMethod I can ensure that ninject has been loaded and is ready to go.. THen in the Start method I do
var workers = DependencyResolver.Current.GetServices<IWorker>();
To get my dependencies, the whole class looks like this
[assembly: WebActivator.PostApplicationStartMethod(typeof(SHB.DALA.Web.App_Start.WorkflowRunner), "Start")]
namespace SHB.DALA.Web.App_Start
{
public static class WorkflowRunner
{
public static void Start()
{
var workers = DependencyResolver.Current.GetServices<IWorker>();
//Do stuff with worker collection
}
}
}
There must be a more elegant solution right?
WebActivator (ASP.NET really) doesn't have any knowledge of Ninject project and therefore cannot have any parameters injected. You would need a Ninject WebActivator extension (the same way you have a Ninject MVC extension) to achieve it. But frankly this is a bit of a catch-22: you want WebActivator to setup Ninject and at the same time Ninject to setup WebActivator.
I can think of 2 possible scenarios for you:
leave the code as it is - I honestly don't know why you don't like your WorkflowRunner class. It is a nice, small class, no other code has any dependency on it, You obtain your references through a DependencyResolver which abstracts you from Ninject itself, your workflow initialization is nicely encapsulated there. I do not smell anything wrong here, really.
Initialize your workflows in the other WebActivator class, where setup Ninject. You know there that your Ninject is initialized and you can still keep workflow initialization code in a separate class.
I would obviously choose 1. if I were you.
If you already have the Ninject bootstrapper working, are you sure you need another solution? For non-controller dependencies, I use a BindingFactory class which has a GetInstance() method. This just calls the Get() method on the Kernel object.
public class BindingFactory
{
private static readonly IKernel Kernel = new StandardKernel(new DefaultServices());
public static T GetInstance<T>()
{
return Kernel.Get<T>();
}
public static IController GetControllerInstance(Type controllerType)
{
return Kernel.Get(controllerType) as IController;
}
}
I then use a NinjectControllerFactory which utilises the BindingFactory.
public class NinjectControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext context, Type controllerType)
{
if (controllerType == null)
return null;
return BindingFactory.GetControllerInstance(controllerType);
}
}
So I'm thinking you could just adapt your current implementation.

Resources