Unity 2.0 Web.config settings with MVC - asp.net-mvc

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.

Related

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.

How to configure Ninject for MVC4 & custom Membership provide?

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);
}

Ninject Kernel Injection of a provider

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.

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.

Ninject 2 + ASP.NET MVC 2 Binding Types from External Assemblies

I'M just trying to get started with Ninject 2 and ASP.NET MVC 2. I have followed this tutorial http://www.craftyfella.com/2010/02/creating-aspnet-mvc-2-controller.html to create a Controller Factory with Ninject and to bind a first abstract to a concrete implementation. Now I want to load a repository type from another assembly (where my concrete SQL Repositories are located) and I just cant get it to work. Here's my code:
Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
}
Controller Factory:
public class Kernelhelper
{
public static IKernel GetTheKernel()
{
IKernel kernel = new StandardKernel();
kernel.Load(System.Reflection.Assembly.Load("MyAssembly"));
return kernel;
}
}
public class MyControllerFactory : DefaultControllerFactory
{
private IKernel kernel = Kernelhelper.GetTheKernel();
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return controllerType == null ? null : (IController)kernel.Get(controllerType);
}
}
In "MyAssembly" there is a Module:
public class ExampleConfigModule : NinjectModule
{
public override void Load()
{
Bind<Domain.CommunityUserRepository>().To<SQLCommunityUserRepository>();
}
}
Now when I just slap in a MockRepository object in my entry point it works just fine, the controller, which needs the repository, works fine. The kernel.Load(System.Reflection.Assembly.Load("MyAssembly")); also does its job and registers the module but as soon as I call on the controller which needs the repository I get an ActivationException from Ninject:
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency CommunityUserRepository into parameter _rep of constructor of type AccountController
1) Request for AccountController
Can anyone give me a best practice example for binding types from external assemblies (which really is an important aspect of Dependency Injection)? Thank you!
Ok, I did some refactoring and now I got it running. I'll post the code of my Global.asax since that's where everything happens. I'm using the latest Ninject 2 Build with the latest Ninject.Web.Mvc Build for MVC 2.
public class MvcApplication : NinjectHttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
RegisterAllControllersIn(System.Reflection.Assembly.GetExecutingAssembly());
}
protected override Ninject.IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(new ExampleConfigModule());
return kernel;
}
}
public class ExampleConfigModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
string connectionString =
ConfigurationManager.ConnectionStrings
["ConnectionString1"].ConnectionString;
string communityUserRepTypeName =
ConfigurationManager.AppSettings
["CommunityUserRepositoryType"];
var communityUserRepositoryType =
Type.GetType(communityUserRepTypeName, true);
Bind<Domain.CommunityUserRepository>().To(communityUserRepositoryType).WithConstructorArgument("conString",connectionString);
}
}
As you can see I got rid of my ControllerFactory, inherited from NinjectHttpApplication and load & bind the external assemblies' type in the Module. Now there might be a better way without specifiyng the type as a string in the config file, maybe you could declare the Module in the external assembly and let Ninject auto-load it from there but I still would need to pass the connection string down to the constructor of the concrete implementation. Maybe someone got an idea for this but for now this works fine.

Resources