I have a repository that i use to access user info IAccountCore and I have a custom membership provider that I've implemented as well. I have property injection setup in the membership provider but it seems that they're never injected. I've followed all the examples on the net to no avail.
I have the ninject bootstrapper + web activator firing the kernel.Inject(Membership.Provider) in the post startup method but the properties are always null. Here are some code snippets:
Bootstrapper in WebApi
[assembly: WebActivator.PostApplicationStartMethod(typeof(API.App_Start.NinjectWebCommon), "RegisterMembership")]
Method being called from above:
public static void RegisterMembership()
{
//bootstrapper.Kernel.Inject(Membership.Provider);
bootstrapper.Kernel.Load(new MembershipNinjectModule());
}
Ninject Module (in a different assembly/project):
public class MembershipNinjectModule : NinjectModule
{
/// <summary>
/// Loads the module into the kernel.
/// </summary>
public override void Load()
{
var kernel = Kernel;
kernel.Inject(Membership.Provider);
}
}
Property in custom membership provider:
[Inject]
public IAccountCore AccountCore {get;set;}
Bindings in another ninject module:
public class NinjectConfigurator : NinjectModule
{
public override void Load()
{
var kernel = Kernel
kernel.Bind<IAccountCore>().To<AccountCore>().InTransientScope();
}
}
Code that loads above module in the Ninject boot strapper:
private static void RegisterServices(IKernel kernel)
{
kernel.Load(new NinjectConfigurator());
}
Try to add on the constructor of your custom membership provider this line :
public MyCustomMembershipProvider()
{
NinjectWebCommon.Kernel.Inject(this);
}
On my project, I used an custom membership provider with Ninject, and I just have this line more than you.
Hope it helps
Related
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.
I am creating a custom ActionResult for my controllers because I've noticed a lot of repeated code that could be made reusable. It looks something like this:
public ExtendedViewResult<T> : ActionResult
{
protected T Model { get; set; }
protected IModelExtender<T> Extender { get; set; }
public ExtendedActionResult(T model, IModelExtender<T> extender)
{
this.Model = model;
this.Extender = extender;
}
}
public class BaseController : Controller
{
public ExtendedViewResult<T> ExtendedView<T>(T model)
{
// I need to create the result here, but how?
var result = new ExtendedViewResult<T>(model, ???????);
return result;
}
}
The problem I am having is that I'm not sure how to construct my ExtendedViewResult object. Since the interface is generic I want to use Dependency Injection to get the proper object, but I'm not sure how to do that since I'm constructing the object myself.
I am using Ninject and Ninject.MVC3 and the default Nuget package creates a Bootstrapper class for me, and when I access the Bootstrapper.Kernel property I get the following warning:
Ninject.Web.Mvc.Bootstrapper.Kernel is obsolete. Do not use Ninject as Service Locator.
If I'm not supposed to access the kernel directly, then how can I change my code so that I can get the appropriate concrete class?
EDIT
Here is the ninject bootstrapper code. The only method I added is the GetInstance()
public static class NinjectMVC3
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule));
DynamicModuleUtility.RegisterModule(typeof(HttpApplicationInitializationModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
// I ADDED THIS CODE, EVERYTHING ELSE IS AUTO-GENERATED
// BY THE NUGET PACKAGE
public static T GetInstance<T>()
{
return bootstrapper.Kernel.Get<T>();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
}
}
Sorry this will be dry on actual code - I've not used ninject much, but other DI containers have this solution, and I'm sure ninject will have this construct as well.
The issue is that you are constructing the object itself. When you're really using a DI container and following IoC, anytime you see the keyword new should be a red flag - and using the container as a service locator is a yellow one.
So how do we get rid of the 'new', since you need a new object? The answer is to have your BaseController take a dependency on a factory that can create an ExtendedViewResult. In Autofac (my container of choice), that would be as simple as having a Func<ExtendedViewResult> injected. I would be surprised if Ninject doesn't have the same. In fact, looks like it does - this ninject wiki page points to this blog post on Ninject.Extensions.Factory.
So that means your code for the Controller could look like this:
public class ConcreteController : BaseController
{
private Func<Foo,ExtendedViewResult<Foo>> _factory;
public BaseController(Func<Foo,ExtendedViewResult<Foo>> factory)
{
_factory = factory;
}
public ExtendedViewResult<Foo> Method(Foo model)
{
var result = _factory(model);
return result;
}
}
If you REALLY want to have a generic method do the creation in your base class, then you will probably need to go the explicit factory interface route from the blog post linked above. With this style code though, you would not need it in most cases, and your controllers explicitly declare the dependencies they need.
You should be using an abstract factory anytime your objects want to create other objects. The abstract factory itself can injected. I've asked a similar question here: Abstract factories when using dependency injection frameworks
It really shouldn't make much of a difference that your factory is generic though.
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 :)
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.
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.