According to this article description custom-membership-provider-with-repository-injection
I implement the custom Membership provide with inject.
Custom Membership provider
using Ninject;
public class CustomMembershipProvider : MembershipProvider
{
[Inject]
public IUserRepository UserRepository { get; set; }
[...]
Custom Role Provider
using Ninject;
public class CustomRoleProvider : RoleProvider
{
[Inject]
public IUserRoleRepository UserRoleRepository { get; set; }
[...]
within Web.Config
<membership defaultProvider="CustomsMembershipProvider">
<providers>
<clear/>
<add name="CustomsMembershipProvider" type="namespace.CustomsMembershipProvider"/>
</providers>
</membership>
<roleManager enabled="true" defaultProvider="customRoleProvider">
<providers>
<clear/>
<add name="customRoleProvider" type="namespace.customRoleProvider"/>
</providers>
</roleManager>
Now within NinjectWebCommon
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<IUserRepository>().To<UserRepository>();
kernel.Bind<IUserRoleRepository>().To<UserRoleRepository>();
// Inject user & role repository into our custom membership & role providers.
kernel.Inject(Membership.Provider);
kernel.Inject(Roles.Provider);
}
when I run application I got error
This method cannot be called during the application's pre-start
initialization stage.
from kernel.Inject(Membership.Provider); this line
But If I Kernel setting put within Application_Start
I got bellow Error
Error activating IUserRepository No matching bindings are available,
and the type is not self-bindable. Activation path: 2) Injection of
dependency IUserRepository into property UserRepository of type
CustomMembershipProvider 1) Request for CustomeMembershipProvider
How to solve that. ??
The result is always null. why? because asp.net has it's own static property for membership.
which is membership.provider. and this instance is not part of instance ninject management.
to workaround it , you need to use kernel.inject . but on the generate aspnetmvc.cs you would see that it's injection on PreApplicationStart event and won't let you.
here is the soloution by cipto that solve the problem for me. add this to your NinjectWebCommon
[assembly: WebActivator.PreApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Start")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "RegisterMembership")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Stop")]
public static void RegisterMembership()
{
bootstrapper.Kernel.Inject(Membership.Provider);
}
Link to article: Ninject and customMembership asp.net mvc 3
I had a lot of trouble trying this and ended up adding a method that gets me a repository
using System.Web.Mvc; //Used to access dependency resolver
private IUserRepository GetUserRepository()
{
return DependencyResolver.Current.GetService<IUserRepository>();
}
I then call this in the methods that require it
I was able to get the repository to become injected using constructor injection but as soon as I went to use the repository the object had been disposed. I found the above to be the simplest alternative.
However, I guess you could also use the Initialize() method
IUserRepository userRepository;
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(name, config);
this.userRepository = DependencyResolver.Current.GetService<IUserRepository>();
}
Or another way would be to use a property
public IUserRepository UserRepository
{
get
{
return DependencyResolver.Current.GetService<IUserRepository>();
}
}
Since a custom RoleProvider often comes along with the custom MembershipProvider, in that case it is useful to add an injection for the Role Provider class. I used the ramon22's solution with an additional line.
[assembly: WebActivator.PreApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Start")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "RegisterMembership")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Stop")]
public static void RegisterMembership()
{
bootstrapper.Kernel.Inject(Membership.Provider);
bootstrapper.Kernel.Inject(Roles.Provider);
}
Related
I'm trying to set up dependency injection with Autofac for project using MVC5 and EF6.
I'm having a hard time figuring out how to decouple correctly the EntityFramework.RoleStore<EntityFramework.IdentityRole> implementation.
I would like have dependency only on Identity.IRoleStore<Identity.IRole> but I'm aware that for generic classes I need to specify the concrete implementation, not the interface.
This is what I tried:
builder.RegisterType<IdentityRole>().As<IRole>();
builder.RegisterType<RoleManager<IRole>>();
builder.RegisterType<RoleStore<IdentityRole>>().As<IRoleStore<IRole>>();
builder.Register(c => new RoleManager<IRole>(c.Resolve<IRoleStore<IRole>>()));
The full error message:
The type 'Microsoft.AspNet.Identity.EntityFramework.RoleStore1[Microsoft.AspNet.Identity.EntityFramework.IdentityRole]' is not assignable to service 'Microsoft.AspNet.Identity.IRoleStore1[[Microsoft.AspNet.Identity.IRole, Microsoft.AspNet.Identity.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]'.
Bit late to the party but this worked for me with Autofac:
builder.RegisterType<RoleStore<IdentityRole>>().As<IRoleStore<IdentityRole, string>>();
My full module for reference:
builder.RegisterType<UserStore<ApplicationUser>>().As<IUserStore<ApplicationUser>>();
builder.RegisterType<RoleStore<IdentityRole>>().As<IRoleStore<IdentityRole, string>>();
builder.RegisterType<ApplicationUserManager>();
builder.RegisterType<ApplicationRoleManager>();
I'm using wrappers for the UserManager and RoleManager
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
}
}
public class ApplicationRoleManager : RoleManager<IdentityRole>
{
public ApplicationRoleManager(IRoleStore<IdentityRole, string> roleStore)
: base(roleStore)
{
}
}
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.
I am trying to use Unity 2.0 for my current project with MVC and having trouble configuring paramter injection in the web.config file.
Here's what I have:
1) A Home Controller:
public class HomeController : Controller
{
IRepository repository = null;
public HomeController()
{
// Always calls this constructor. Why?
// Should be calling the constructor below that takes IRepository.
}
public HomeController(IRepository repository)
{
// Should be calling this constructor!!!
this.repository = repository;
}
public ActionResult Index()
{
List<int> intList = this.repository.GetInts();
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
A basic controller with two constructors. The 1st one takes no arguments, and the 2nd one takes IRepository as an argument (that's supposed to be injected by Unity)
2) SQL Repository
public class SQLRepository : IRepository
{
private string connectionString = null;
public SQLRepository(string connectionString)
{
this.connectionString = connectionString;
}
#region IRepository Members
public List<int> GetInts()
{
return new List<int>() { 1, 2, 3, 4, 5 };
}
#endregion
}
A future to be SQL repository, but for now it just implements 1 member of the IRepository interface, namely GetInts() and returns a list of integers.
3) IRepository Interace
public interface IRepository
{
List<int> GetInts();
}
An interface.
4) Application_Start() Event in my Global.asax file.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
IUnityContainer container = new UnityContainer();
UnityConfigurationSection section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
section.Configure(container, "Default");
}
This is used to read the Unity 2.0 configuration from the web.config file in order to register and map types etc.
6) The Unity 2.0 Configuration Section in web.config
<unity>
<typeAliases>
<typeAlias alias="string" type="System.String, mscorlib" />
<typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
<typeAlias alias="IRepository" type="NewMVCApp.Interfaces.IRepository, NewMVCApp" />
<typeAlias alias="SQLRepository" type="NewMVCApp.Repository.SQLRepository, NewMVCApp" />
</typeAliases>
<containers>
<container name="Default">
<types>
<type type="IRepository" mapTo="SQLRepository">
<lifetime type="singleton" />
<constructor>
<param name="connectionString">
<value value="ApplicationServices" />
</param>
</constructor>
</type>
</types>
</container>
</containers>
This is Unity 2.0 configuration section that I use. As you can see It typeAlias for both my IRepository and my SQLRepository classes and then maps IRepository to SQLRepository. So that anytime IRepository is requested, SQLRepository instance will be supplied. Also, I want to pass a connection string via the constructor to my SQLRepository.
5) So, what am I trying to do?
I am trying to use Unity 2.0 to pass in the instance of IRepository (SQLRepository) to my HomeController. But for some reason the default, parameterless constructor, for the HomeController() gets invoked. But HomeController(IRepository repository) never gets called. I am pretty sure that I did not set things up properly in the web.config file. But I am not sure how do set things up properly so the correct constructor on the HomeController gets called. Please help:)
&Thank you:)
Your Unity configuration looks fine. The problem is that you haven't hooked up Unity to the MVC framework, so the framework isn't using the container to create your controller, instead MVC is using the default logic, which calls the default constructor.
You need two things. First, an implementation of IControllerFactory. I usually use this one:
public class UnityControllerFactory : DefaultControllerFactory
{
private readonly IUnityContainer container;
public UnityControllerFactory(IUnityContainer container)
{
this.container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if(controllerType != null)
return container.Resolve(controllerType) as IController;
return base.GetControllerInstance(requestContext, controllerType);
}
}
Second, you need to tell the MVC framework to use this controller factory instead of it's default one. You do this in your Application_Start handler. Do this:
ControllerBuilder.Current.SetControllerFactory(
new UnityControllerFactory(container));
Once you've done that, your controllers will be created through the container and everything should start working.
Thank you so much Chris!! That was it! Here's the how the Application_Start() event should look like in MVC2 using Unity 2.0:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
IUnityContainer container = new UnityContainer();
IControllerFactory controllerFactory = new UnityControllerFactory(container);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
// Do the line below only if you want to Register IoC programatically
//container.RegisterType<IRepository, SQLRepository>(new ContainerControlledLifetimeManager());
UnityConfigurationSection section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
section.Configure(container, "Default");
}
Try with Unity.Mvc nuget packages. You can use container.LoadConfiguration(); in UnityConfig class.
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.LoadConfiguration();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
Then you can update web.config as below.
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity configSource="unity.config" />
Complete article can be found # MVC 5 with Unity for Dependency Injection.
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.
My web app solution consists of 3 projects:
Web App (ASP.NET MVC)
Business Logic Layer (Class Library)
Database Layer (Entity Framework)
I want to use Ninject to manage the lifetime of the DataContext generated by the Entity Framework in the Database Layer.
The Business Logic layer consists of classes which reference repositories (located in the database layer) and my ASP.NET MVC app references the business logic layer's service classes to run code. Each repository creates an instance of the MyDataContext object from the Entity Framework
Repository
public class MyRepository
{
private MyDataContext db;
public MyRepository
{
this.db = new MyDataContext();
}
// methods
}
Business Logic Classes
public class BizLogicClass
{
private MyRepository repos;
public MyRepository
{
this.repos = new MyRepository();
}
// do stuff with the repos
}
Will Ninject handle the lifetime of MyDataContext despite the lengthy dependency chain from the Web App to the Data Layer?
EDIT
I has some problems with it some time ago, but now it seems to work:
Bind<CamelTrapEntities>().To<CamelTrapEntities>().Using<OnePerRequestBehavior>();
Instead of using HttpModule, you can use OnePerRequestBehavior and it will take care of handling context in current request.
EDIT 2
OnePerRequestBehavior needs to be registered in web.config, because it depends on HttpModule too:
In IIS6:
<system.web>
<httpModules>
<add name="OnePerRequestModule" type="Ninject.Core.Behavior.OnePerRequestModule, Ninject.Core"/>
</httpModules>
</system.web>
With IIS7:
<system.webServer>
<modules>
<add name="OnePerRequestModule" type="Ninject.Core.Behavior.OnePerRequestModule, Ninject.Core"/>
</modules>
</system.webServer>
PREVIOUS ANSWER
It is your responsibility to dispose context when it is not needed. Most popular way in ASP.NET is to have one ObjectContext per request. I do it by having HttpModule:
public class CamelTrapEntitiesHttpModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest += ApplicationBeginRequest;
application.EndRequest += ApplicationEndRequest;
}
private void ApplicationEndRequest(object sender, EventArgs e)
{
((CamelTrapEntities) HttpContext.Current.Items[#"CamelTrapEntities"]).Dispose();
}
private static void ApplicationBeginRequest(Object source, EventArgs e)
{
HttpContext.Current.Items[#"CamelTrapEntities"] = new CamelTrapEntities();
}
}
This is injection rule:
Bind<CamelTrapEntities>().ToMethod(c => (CamelTrapEntities) HttpContext.Current.Items[#"CamelTrapEntities"]);
My Repository takes ObjectContext in constructor:
public Repository(CamelTrapEntities ctx)
{
_ctx = ctx;
}
Just want to mention that Autofac with the ASP.Net integration have the request lifetime support built-in. Resolve instances in the RequestContainer and they will be disposed (if implementing IDisposable) at the end of the request.
You should make your classes DI friendly though:
public class MyRepository
{
private MyDataContext db;
public MyRepository(MyDataContext context)
{
this.db = context;
}
// methods
}
public class BizLogicClass
{
private MyRepository repos;
public BizLogicClass(MyRepository repository)
{
this.repos = repository;
}
// do stuff with the repos
}