I'm using Ninject for dependency injection in my application. Here's an example of one of my controllers:
public class DepartmentsController : Controller
{
private IDepartmentsRepository departmentsRepository;
public DepartmentsController(IDepartmentsRepository departmentsRepository)
{
this.departmentsRepository = departmentsRepository;
}
...
}
I'm also trying to follow this tutorial to use ELMAH in an MVC application. The idea is to use a custom controller factory to handle errors from every controller. You then set the controller factory to the custom one in the global.asax.cs file.
The only problem is that it is expecting a parameterless constructor in each controller, which I can't do (that I know of) with dependency injection with Ninject.
How can I get around this?
If you are using MVC3, you should ignore the part about the Controller Factory and use Global Filters to apply the custom attribute to each controller.
If you aren't using v3 yet and you can modify their code to inherit from the Ninject Controller factory.
Related
I am writing some integration tests. I am using Dependency Injection with Windsor Castle.
I would like to resolve the test class using an inversion of control container. I do not think that resolve all my dependencies inside the test class is the solution for my case.
I would like to do what I have done inside the web api project. I implemented IHttpControllerActivator, which is an extension point to fully control controller's life-cycle. That is, we can define how a controller is instantiated.
I would like to do the same for the tests. But I do not understand which is the interface I have to implement. Can anyone help me?
I think I just need to know which is the corresponding IHttpControllerActivator for unit test.
EDIT
I have a web api project to test. The web api project resolves all the dependencies with WindsorCastle. Now I need to test the web api. This is what I am doing:
public voi MyTest_Ok()
{
//Arrange
var myController = new MyWebApiController();
var result = await myController.DoWork();
//Asserts
}
Obviously it does not work because I am not using castle windsor to resolve the controller and so I do not resolve any dependency from web api controller to bottom.
I think I could replace this line
var myController = new MyWebApiController();
with something like this
var myController = windsorContainer.Resolve<MyWebApiController>();
But this solution I think is wrong. I think it's better to resolve dependencies as happen inside the controller:
public class MyWebApiController : ApiController()
{
public InjectedDependency dep { get; set; }
public DoWork()
{
dep.DoWork();
}
}
I can do this because I have implemented a custom IHttpControllerActivator.
Answer is: your test framework does. As I know none of the common test frameworks allows you take control over creating your test classes.
More info about this here as well:
A .NET Unit Test without a parameterless constructor, to facilitate dependency injection
NUnit provide ParameterizedTestFixture -https://github.com/nunit/docs/wiki/TestFixtureData
So in theory as a dirty workaround you would be able to inject some dependencies trough constructor by this, but it wasn't designed for this purpose.
In general you have to go for service locator.
I'm playing with the Asp.Net MVC 6 boilerplate project. I'm trying to configure the dependency injection for one of my services. It seems like the built in IoC container is ignoring my binding.
Startup.cs
public void ConfigureServices(IServiceCollection services){
/*boilerplate's default bindings*/
services.AddTransient<IDummy, Dummy>(p => new Dummy()
{
name = "from injection"
});
}
HomeController.cs
public IActionResult Index(IDummy dummy){
var test = dummy.name;
return this.View(HomeControllerAction.Index);
}
Exception:
ArgumentException: Type
'Presentation.WebUI.Controllers.IDummy' does not have a
default constructor
Could you please tell me what is am I doing wrong?
That exception is because the framework cannot bind action arguments to interfaces.
You are trying to do the injection on the Action when the framework by default uses constructor injection.
Reference: Dependency Injection and Controllers
Constructor Injection
ASP.NET Core’s built-in support for constructor-based dependency
injection extends to MVC controllers. By simply adding a service type
to your controller as a constructor parameter, ASP.NET Core will
attempt to resolve that type using its built in service container.
public class HomeController : Controller {
IDummy dummy;
public HomeController(IDummy dummy) {
this.dummy = dummy
}
public IActionResult Index(){
var test = dummy.name;
return this.View(HomeControllerAction.Index);
}
}
ASP.NET Core MVC controllers should request their dependencies
explicitly via their constructors. In some instances, individual
controller actions may require a service, and it may not make sense to
request at the controller level. In this case, you can also choose to
inject a service as a parameter on the action method.
Action Injection with FromServices
Sometimes you don’t need a service for more than one action within
your controller. In this case, it may make sense to inject the service
as a parameter to the action method. This is done by marking the
parameter with the attribute [FromServices] as shown here:
public IActionResult Index([FromServices] IDummy dummy) {
var test = dummy.name;
return this.View(HomeControllerAction.Index);
}
This is similar to Dependency Injection with Custom Membership Provider, but the responses there don't solve the issue for me.
I have a custom membership provider which has a dependency to a repository class. ASP.NET will always instantiate this using the parameter-less constructor, so to resolve the dependency to the repository I have a kind of service locator method ... my ctor looks like this:
public CustomMembershipProvider()
{
_userRepository = AppStart_NinjectMVC3.Resolve<IUserRepository>();
}
And that Resolve method looks like this..
public static T Resolve<T>() where T : class
{
return _kernel.Get<T>();
}
This works fine when I run the web app, because _kernel is correctly setup. However, I need to test the methods on my membership provider.. So when my test code tries to invoke the methods on membership provider it will instantiate a new membership provider class with the paramter-less ctor, which errors because _kernel is not setup.
What I want to do is somehow inject my FakeUserRepository class instead, but how can I achieve that?
I think I have a work round for this...
I've added a ctor to the membership provider which accepts a repository instance, and then I've manually instantiated my membership provider in my test class like this:
var prov = new CableSenseMembershipProvider(new FakeUserRepository());
var config = new NameValueCollection();
config.Add("applicationName", "ddd");
config.Add("name", "CustomMembershipProvider");
config.Add("requiresQuestionAndAnswer", "false");
config.Add("requiresUniqueEmail", "false");
prov.Initialize(config["name"], config);
Once I've dont this I can then invoke that instance and not worry about the parameter-less ctor being called.
As an aside, you still need to add the membership section to your test project app.config or it wont work - which is somewhat confusing!
Why not extract everything out of your custom membership provider into an implementation class and instantiate that class via the service locator then pass all your calls through to that? The implementation class can then be unit-testable and the ugly Membership stuff can be 'right by inspection'.
I am using the MVC AccountController that implements the ASP.NET Membership Provder.
I have a repository with all my database access in which I have added a Countries property that returns a list of countries. I want to add a country dropdown to the Register page so I need to be able to get this data from my repository and pass it to the View.
I have been using contructor injection in my other controllers but I dont know how to apply this to the existing AccountController.
// This constructor is used by the MVC framework to instantiate the controller using
// the default forms authentication and membership providers.
public AccountController()
: this(null, null)
{
}
// This constructor is not used by the MVC framework but is instead provided for ease
// of unit testing this type. See the comments at the end of this file for more
// information.
public AccountController(IFormsAuthentication formsAuth, IMembershipService service)
{
FormsAuth = formsAuth ?? new FormsAuthenticationService();
MembershipService = service ?? new AccountMembershipService();
}
Can I change the existing AccountController constructor to access my repository?
Register the services in your IoC engine and then remove the default constructor.
If you have already registered your repository with ninject, you should be able to just add a third parameter to the constructor of the controller. I saw your earlier comment about ninject, but I'm not using NinjectModule. If you're using MVC 3, would suggest that you take a look at nuget (http://nuget.codeplex.com) and download the Ninject.MVC3 packge which adds a AppStartNinjectMvc3 class to your project where you can register services with the kernel.Bind methods:
kernel.Bind<IThingRepository>().To<SqlThingRepository>();
Hope this helps.
If your using MVC2 you should take a look at http://mvcstarter.codeplex.com/ it's also using Ninject. Like #Johan said you simply have to put the parameter and bind it in the global.asax.cs.
Hope it helps!
Should I do something along the lines of this? I'm thinking of all my controllers inheriting from BaseController. Does this break the design pattern of IoC? What else should I do instead?
public class BaseController: Controller
{
protected ICookieService CookieService {
get {
return ServiceResolver.Resolve<ICookieService>(new { HttpContext = HttpContext });
}
}
protected IDateTimeService DateTimeService {
get {
return ServiceResolver.Resolve<IDateTimeService>();
}
}
protected ISettingsService SettingsService {
get {
return ServiceResolver.Resolve<ISettingsService>();
}
}
}
It would be a lot simpler to go with constructor injection and have a controllerfactory inject it for you. If you can, don't use a service locator (your ServiceResolver ) if you can get away with constructor injection.
There's some info on it on Adding a controller factory to ASP MVC
The link shows how to do it with StructureMap and it looks like you're using Unity, but it should be straightforward to adapt.
I'm assuming that the protected interfaces you have are dependencies for the controller. Its possible to set up an IoC container to inject the dependencies for you. It can certainly be done with Castle Windsor. You would need to change you BaseController class to have a constructor with the required dependencies, as long as the IoC container knows about the other services it'll be able to inject them.
One of the principles behind Inversion of Control and Component-Driven Development is about using static service locators only when there is no other way (i.e.: in web service hosts or object data sources).
Technically speaking, using static service locators the base controller does not violate IoC, it just does not use it.
Check out existing integration between Autofac IoC container and ASP.NET MVC (other containers should be able to do that as well).