Ninject Kernel Injection of a provider - asp.net-mvc

I'm trying to use the [Inject] attribute on a BasicRoleProvider : RoleProvider provider.
In my provider, I did:
public class BasicRoleProvider : RoleProvider
{
[Inject]
private IAuthenticationService authenticationService;
/*Other stuff here*/
}
My Global.asax.cs file is as follows:
public class MvcApplication : NinjectHttpApplication
{
/* Other stuff here */
#region Inversion of Control
protected override IKernel CreateKernel()
{
return Container;
}
static IKernel _container;
public static IKernel Container
{
get
{
if (_container == null)
{
_container = new StandardKernel(new SiteModule());
}
return _container;
}
}
internal class SiteModule : NinjectModule
{
public override void Load()
{
//Set up ninject bindings here.
Bind<IAuthenticationService>().To<AuthenticationService>();
this.Kernel.Inject(Roles.Provider);
}
}
#endregion
}
Whenever a method in the BasicRoleProvider gets executed and is using the authenticationService, its null. I think my problem lies in the Global.ascx.cs file. Am I doing the injection right?

It seems possible that you are using Ninject in an unsupported way.
From https://github.com/ninject/ninject/wiki/Changes-in-Ninject-2
Things that were in Ninject 1.x that are not in Ninject 2:
Field injection: This is a bad
practice, and has been cut for
minimization.
Because you tagged your question MVC 3, I assume you are linking to Ninject 2. As far as I know, Ninject 1 in an MVC 3 app would be a dead end.
The Inject attribute still exists, and fields must still be a valid target for it, which is why you do not get a compile time error.
But Ninject 2 will happily ignore that Inject attribute on the fields, which is why it is null for you.

Related

Resolve constructor argument with parameter from base class

I have a custom ASP.NET MVC controller that retrieves operations from the user service. I want to pass the operations property to the scenario service using dependency injection.
public abstract class BaseController : Controller {
protected IUserService userService;
public OperationWrapper operations { get; private set; }
public BaseController(IUserService userService) {
this.userService = userService;
this.operations = userService.GetOperations(HttpContext.Current.User.Identity.Name);
}
}
public abstract class ScenarioController : BaseController {
protected IScenarioService scenarioService;
public ScenarioController(IScenarioService scenarioService, IUserService userService)
: base(userService) {
this.scenarioService = scenarioService;
}
}
public class ScenarioService : IScenarioService {
private OperationWrapper operations;
public ScenarioService(OperationWrapper operations) {
this.repo = repo;
this.operations = operations;
}
}
Here is my Windsor installer.
public class Installer : IWindsorInstaller {
public void Install(IWindsorContainer container, IConfigurationStore store) {
container.Register(Classes.FromThisAssembly()
.BasedOn<IController>());
container.Register(Classes.FromThisAssembly()
.Where(x => x.Name.EndsWith("Service"))
.WithService.DefaultInterfaces()
.LifestyleTransient());
}
}
I pretty sure I've done something similar with Ninject a couple of years back. What do I need to add to the installer in order to make this work? Is it even possible?
There are a few of options here:
1. Use LifeStylePerWebRequest() and UsingFactoryMethod()
First, you could register an OperationWrapper as LifestylePerWebRequest() and inject it into both the BaseController and ScenarioService. Windsor will let you register the dependency with a factory method for creating it, which can in turn call other services which have been registered.
container.Register(Component.For<OperationWrapper>()
.LifestylePerWebRequest()
.UsingFactoryMethod(kernel =>
{
var userService = kernel.Resolve<IUserService>();
try
{
return userService.GetOperations(
HttpContext.Current.User.Identity.Name);
}
finally
{
kernel.ReleaseComponent(userService);
}
}));
So, every time Windsor is asked for an OperationWrapper, it will run that call against an instance if IUserService, giving it the Name of the current User. By binding the lifestyle to LifestylePerWebRequest(), you can verify that each request will get its own instance of the OperationWrapper and it won't bleed across requests.
(The only edge case you'd run into is one where a user becomes authenticated mid-request and the OperationWrapper needs to be adjusted as a result. If that's a normal-path use case, this may need some re-thinking.)
Then, modify your base controller to take that registered object in as a dependency:
public abstract class BaseController : Controller {
protected IUserService userService;
protected OperationWrapper operations;
public BaseController(IUserService userService, OperationWrapper operations) {
this.userService = userService;
this.operations = operations;
}
}
2. Use Method Injection
It looks like OperationWrapper is some sort of context object, and those can sometimes be injected into the method instead of into the constructor.
For instance, if your method was:
int GetTransactionId() { /* use OperationWrapper property */ }
You could just modify the signature to look like:
int GetTransactionId(OperationWrapper operations) { /* use arg */ }
In this situation, it makes sense to use it if a small-ish subset of your service's methods use that dependency. If the majority (or totality) of methods need it, then you should probably go a different route.
3. Don't use DI for OperationWrapper at all
In situations where you have a highly-stateful contextual object (which it seems like your OperationWrapper is), it frequently just makes sense to have a property whose value gets passed around. Since the object is based on some current thread state and is accessible from everywhere in any subclassed Controller, it may be right to just keep the pattern you have.
If you can't answer the question "What am I unable to do with OperationWrapper now that DI is going to solve for me?" with anything but "use the pattern/container," this may be the option for this particular situation.
You should set dependency resolver in Application_Start method of global.asax
System.Web.MVC.DependencyResolver.SetResolver(your windsor resolver)
Create a class that inherits from DefaultControllerFactory. Something like this will do:
public class WindsorControllerFactory : DefaultControllerFactory
{
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(
404,
String.Format(
CultureInfo.CurrentCulture,
"The controller for path '{0}' was not found or does not implement IController.",
requestContext.HttpContext.Request.Path
)
);
}
return (IController)_kernel.Resolve(controllerType);
}
public override void ReleaseController(IController controller)
{
Kernel.ReleaseComponent(controller);
}
private readonly IKernel _kernel;
private IKernel Kernel
{
get { return _kernel; }
}
}
In the Application_Start method of your MvcApplication class add the following:
var container = new WindsorContainer();
container.Install(FromAssembly.This());
ControllerBuilder.Current.SetControllerFactory(
new WindsorControllerFactory(container.Kernel)
);
This should work with your existing installer and get you to the point where Windsor will start resolving your dependencies for you. You might have to fill-in a few gaps, but you'll get the point.
I've borrowed heavily from: https://github.com/castleproject/Windsor/blob/master/docs/mvc-tutorial-intro.md
Be wary of using IDependencyResolver as it doesn't make provision for releasing what's resolved.

Dependency Injection Constructor Conflict

I have a controller and I want to use Dependency Injection with constructor,this is my code
private readonly IHomeService _iHomeService;
public HomeController(IHomeService iHomeService)
{
_iHomeService = iHomeService;
}
public HomeController()
{
}
When I remove Constructor without any parameter(Second Constructor),I see this error :
No parameterless constructor defined
and When I use Constructor without any parameter,I see my private field is null(_iHomeService = null) because program use constructor without parameter.
How can I resolve this problem for Dependency Injection?
Well, to do dependency injection youll need to either use a framework or use controller factory .
try ninject
public class HomeController : Controller
{
private readonly IWelcomeMessageService welcomeMessageService;
public HomeController(IWelcomeMessageService welcomeMessageService)
{
this.welcomeMessageService = welcomeMessageService;
}
public void Index()
{
ViewModel.Message = this.welcomeMessageService.TodaysWelcomeMessage;
return View();
}
}
public class WelcomeMessageServiceModule : NinjectModule
{
public override void Load()
{
this.Bind<IWelcomeMessageService>().To<WelcomeMessageService>();
}
}
The framework will take control on the controller instance creation and pass the constractor params
It sounds like you are expecting, automatically, the HomeService class to be instantiated and injected into the Controller.
Using an IoC framework like Ninject or StructureMap will do that for you - once you've set it up.
If you don't want to use an IoC framework, you'll need to manually instantiate the HomeService in your constructor.
ASP.NET uses a ControllerFactory to instantiate your controllers on-demand. This class requires that your controller has a parameterless constructor that it can use to create an instance of it.
You'll need to use a dependency injection framework to create your controllers and inject the required dependencies. ASP.NET has some dependency injection capability, but I understand that it is flawed. I suggest using Castle Windsor to manage your dependency injection. It integrates very well with ASP.NET, and there's a tutorial on integrating it here.
If you go down this route, you'd end up with an installer for your controllers and service:
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<IController>().LifestyleTransient());
container.Register(Component.For<IHomeService>.ImplementedBy<HomeService>());
}
}
..and a new ControllerFactory to create them:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
}
return (IController) _kernel.Resolve(controllerType);
}
}
Finally, you'd create a container and set a new controller factory:
var container = new WindsorContainer().Install(new Installer());
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
You could also use Ninject or StructureMap.

MVC 3 CookieTempDataProvider and Ninject IOC

I am trying to use the CookieTempDataProvider in MVC 3 futures assembly. I believe I have "wired" it up successfully using ninject. Below is the code from my app_start.cs file:
[assembly: WebActivator.PreApplicationStartMethod(typeof(Web.AppStart), "Start")]
namespace Web {
public static class AppStart {
public static void RegisterServices(IKernel kernel) {
kernel.Bind<ITempDataProvider>().To<CookieTempDataProvider>();
}
public static void Start() {
// Create Ninject DI Kernel
// IKernel kernel = new StandardKernel();
IKernel kernel = Container;
// Register services with our Ninject DI Container
RegisterServices(kernel);
// Tell ASP.NET MVC 3 to use our Ninject DI Container
DependencyResolver.SetResolver(new NinjectServiceLocator(kernel));
}
static IKernel _container;
public static IKernel Container
{
get
{
if (_container == null)
_container = new StandardKernel();
return _container;
}
}
However, when I access my page that uses TempData, I get the this error indicating that it is still trying to use the SessionTempDataProvider:
Server Error in '/' Application.
The SessionStateTempDataProvider class requires session state to be enabled.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The SessionStateTempDataProvider class requires session state to be enabled.
I must be missing something and I can't figure out what it is. Any help would be most appreciated.
Many Thanks
I've only been able to get this to work with the BaseController approach. The controller creation processes does't ask Ninject for a ITempDataProvider.
public class BaseController : Controller
{
protected override ITempDataProvider CreateTempDataProvider()
{
return new CookieTempDataProvider(HttpContext);
}
}
Extend the controller class
public static void SetMessage(this Controller controller, String message)
{
controller.TempData["Messag"] = message;
}
Then you can use it like this:
public ActionResult Save()
{
//Validation...
Save(Foo);
this.SetMessage("Item saved successfully");
return Redirect("/Site");
}
No number three :)

Ninject with MembershipProvider | RoleProvider

I'm using ninject as my IoC and I wrote a role provider as follows:
public class BasicRoleProvider : RoleProvider
{
private IAuthenticationService authenticationService;
public BasicRoleProvider(IAuthenticationService authenticationService)
{
if (authenticationService == null) throw new ArgumentNullException("authenticationService");
this.authenticationService = authenticationService;
}
/* Other methods here */
}
I read that Provider classes get instantiated before ninject gets to inject the instance. How do I go around this? I currently have this ninject code:
Bind<RoleProvider>().To<BasicRoleProvider>().InRequestScope();
From this answer here.
If you mark your dependencies with [Inject] for your properties in your provider class, you can call kernel.Inject(MemberShip.Provider) - this will assign all dependencies to your properties.
I do not understand this.
I believe this aspect of the ASP.NET framework is very much config driven.
For your last comment, what they mean is that instead of relying on constructor injection (which occurs when the component is being created), you can use setter injection instead, e.g:
public class BasicRoleProvider : RoleProvider
{
public BasicRoleProvider() { }
[Inject]
public IMyService { get; set; }
}
It will automatically inject an instance of your registered type into the property. You can then make the call from your application:
public void Application_Start(object sender, EventArgs e)
{
var kernel = // create kernel instance.
kernel.Inject(Roles.Provider);
}
Assuming you have registered your role provider in the config. Registering the provider this way still allows great modularity, as your provider implementation and application are still very much decoupled.

Ninject.Web.Mvc add-on not working with ASP.NET MVC 2

I'm using the Ninject.Web.Mvc (the MVC 2 version) add-on with ASP.NET MVC 2. This is an excerpt of my Global.asax.cs:
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes;
// RegisterAllControllersIn() is not available in the MVC 2 version of Ninject
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<IRepository>().To<NHibernateRepository>();
return kernel;
}
I also have a base RepositoryController:
public class RepositoryController : Controller
{
protected IRepository Repository { get; set; }
public RepositoryController()
{
}
public RepositoryController(IRepository repository)
{
Repository = repository;
}
}
So as you can see, it's a very simple setup where RepositoryController expects to be injected with an instance of an IRepository, and Ninject is configured to use a concrete instance of NHibernateRepository. However, this doesn't work and the Repository property is null whenever I try to access it in a controller. However, if I change the code to this instead:
[Inject]
public IRepository Repository { get; set; }
Then it works fine. Does anyone know why constructor injection isn't working, but property injection is?
Try removing the parameterless constructor.
Ninject might be picking the wrong constructor to resolve.
To test it out, you could put a breakpoint in both constructors and see which one fires, but I have a feeling it's the parameterless one.

Resources