Asp.net MVC boilerplate dependency injection not working - c#

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

Related

access appsetting from data layer without creating instantiation with parameter

How can i access my "appsettings.js" values in Business/Data layer without creating instantiation in the constructor level.
I can access all values in the controller but i don't want to send to all my layers like passing constructor parameter.
I am trying to understand this post but i don't understand fully. can some one provide me some sample code with out creating instantiation
ASP.NET 5 DI app setting outside controller
Controller - Services - DBServices (without parameter constructor?)
appsetting.json
"DbSettings":{
"ConnectionString" : "TESTING Connection string here"
}
Controller:
public class TestController : ControllerBase
{
public TestController(IOptions<DbSettings> dbSettings)
{
_balService = new BALServices(dbSettings.Value); // passing parameter "dbsetting" to constructor which i don't want.
}
}
Startup.cs
services.Configure<DbSettings>(Configuration.GetSection("DbSettings"));
services.AddSingleton<IConfiguration>(Configuration);
Dbsettings.cs
public class DbSettings
{
public string ConnectionString { get; set; }
}
The framework isn’t really designed to allow you to do that. ASP.NET Core uses dependency injection and kind of forces you to follow it, since pretty much everything is inaccessible outside of the DI container. So whenever something depends on something, then it should make that dependency clear by expecting it in the constructor. That is the way it is designed.
That being said, you creating a new instance of BALServices isn’t really in the spirit of dependency injection either. If you want to use BALServices in the controller, then instead of creating an instance of it itself, the controller should just depend on that type.
So you would change the controller to look like this:
public class TestController : ControllerBase
{
private readonly BALServices _balService;
public TestController(BALServices balService)
{
_balService = balService;
}
}
Now, the controller does not need to worry about how it could possibly create that object. It just depends on it being there and letting someone else figure that out. And that’s exactly what dependency injection is about.
In order to make that work, of course you now need to adjust your BALServices to depend on those IOptions<DbSettings> instead:
public class BALServices
{
private readonly DbSettings _dbSettings;
public BALServices(IOptions<DbSettings> dbSettings)
{
_dbSettings = dbSettings.Value;
}
}
And then you only need to register this service in your Startup:
services.AddScoped<BALServices>();
And now you have TestController depend on the actual service it wants to use, and BALServices depend on the configuration it requires. And the DI container will automatically provide you with what you need.

How do I get access to INodeServices without dependency injection

I'd like to run some node code from my c#. Microsoft.AspNetCore.NodeServices seems to be the way to do this job however the examples are all very similar and all involve putting
services.AddNodeServices();
in the configure services function and then DI adds the implementation of INodeServices to a controller. Like this
public class foo
{
private readonly INodeServices _nodeServices;
public foo(INodeServices nodeServices)
{
_nodeServices = nodeServices;
}
}
As I'm using this in a class library rather than a webapi how is DI going to work? Also how do I call the class from a unit test, what can I pass into the constructor? I'm sure I'm missing something obvious.
The concept of DI is that it can be used to resolve object graphs. That is, it doesn't just resolve dependencies of the Controller class, but dependencies of those dependencies, dependencies of those dependencies, etc.
To use INodeServices in your own library, you simply need to reference Microsoft.AspNetCore.NodeServices, then accept it as a constructor parameter.
public class MyServiceFromMyLibrary : IMyServiceFromMyLibrary
{
private readonly INodeServices nodeServices;
public MyServiceFromMyLibrary(INodeServices nodeServices)
{
this.nodeServices = nodeServices;
}
// ...
}
Then reference your library from the Web API project and inject your service into a controller.
public class FooController
{
private readonly IMyServiceFromMyLibrary myService;
public FooController(IMyServiceFromMyLibrary myService)
{
this.myService = myService;
}
}
DI takes care of putting the INodeServices instance into your class provided it is registered in your composition root, as follows.
services.AddNodeServices();
services.AddTransient<IMyServiceFromMyLibrary, MyServiceFromMyLibrary>();
If your end game is to create a reusable library rather than an application layer refer to DI Friendly Library for some techniques to make your library easier to use without the use of dependency injection.
Also how do I call the class from a unit test, what can I pass into the constructor?
For a unit test, you would just need to mock INodeServices. The simplest way is to use a mocking library, such as Moq.
var mock = new Mock<INodeServices>();
mock.Setup(ns => ns.InvokeAsync(It.IsAny<string>())).Returns(...);
var target = new MyServiceFromMyLibrary(mock.Object);
// .. Call a method on target and then assert the results
References:
Using Node Services in ASP.NET Core
Dependency injection in ASP.NET Core

ASP.NET Mvc Generic Controllers and Ninject injection InRequestScope at the same time

A while ago, I built a ControllerFactory with the goal of use Generic Controllers in my Asp.Net MVC project. This factory is something like this:
public class MyControllerFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
if (/*controller is generic, I know it by a convention in the controllerName*/)
{
string typeName = //resolve Type name from controllerName and requestContext;
Type controllerType = typeof(MyGenericController<>).MakeGenericType(Type.GetType(typeName));
var ninjecKernel = //get a ninject kernel;
return (IController)ninjecKernel.Get(controllerType);
}
else
{
//build a normal controller
}
}
}
I use this controller factory in the Globar.asax file like this ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
But in the services injected by ninject to the controller are InSingletonScope. Now I decided to inject those services InRequestScope, so, the services can share the same EntityFramework context. To archive this, I'm trying to use this approach, when services are injected in request scope, using the Ninject.Web.Mvc.dll. In this approach ninject is who build the controllers internally by inheriting MvcApplication of Global.asax from NinjectHttpApplication, so I don't know how to keep the Generic Controller code.
How can I archieve both goals?
Don't inherit your Global.asax from NinjectHttpApplication. You will still be able to use InRequestScope to control lifetimes.

Accessing a repository in AccountController through constructor

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!

Using a parameterless controller constructor with Ninject?

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.

Categories

Resources