C# Web Api 2 use StructureMap to pass request data into injected dependency constructor parameter - structuremap

I'm getting my feet wet with C# IoC frameworks. I chose StructureMap.Webapi2 to integrate into an existing api.
I have the following scenario which I am not sure what the best way to implement is.
public class MyController : ApiController
{
public IHttpActionResult MyAction(string clientCode, [FromBody]MyDto bodyData)
{
var client = new ClientManager().GetClientByCode(clientCode);
var someData = new SomeData
{
User = bodyData.User,
ClientCode = clientCode,
SomeField = client.SomeField
};
var myService = new WorkerService(someData);
myService.DoSomething();
return Ok();
}
}
A peek a the WorkerService:
public WorkerService(SomeData someData)
{
_someData = someData;
_someCollection = GetSomeData(); // GetSomeData uses _someData
}
public DoSomething()
{
// some code that uses _someData and _someCollection
}
Approach 1:
Make WorkerService's constructor parameterless and add a public SomeData property that can be initialized inside MyController MyAction.
Then both ClientManager and WorkerService can be injected by the IoC into a constructor to be added to the controller.
The Action would then look like:
public IHttpActionResult MyAction(string clientCode, [FromBody]MyDto bodyData)
{
var client = _clientManager.GetClientByCode(clientCode);
var someData = new SomeData
{
User = bodyData.User,
ClientCode = clientCode,
SomeField = client.SomeField
};
_myService.SomeData = someData;
_myService.DoSomething();
return Ok();
}
Approach 2 (the one I'm not sure how to implement)
Keep WorkerService constructor as is (with a parameter). Inject the service into the Controller's constructor (requires building and pass the service's argument (SomeData) at runtime, instead of having the MyAction build SomeData).
Somehow build SomeData (maybe using a factory) before for each request is handled by the controller. This would mean that ClientManager would have to be injected to that somehow/factory. The output of the somehow/factory would be used by the IoC when building the WorkerService to be injected into the controller, per request.
To me, Approach 1 seems quicker and simple, but Approach 2 seems to be more attractive, more challenging and with more learnings.

I ended up finding a solution for the problem:
Create a passive attribute and add to the action
Create an ActionFilter, which checks for the attribute and when found, gets data from the request.
Since I didn't like the approach of reading the request body in the ActionFilter, I changed the request and moved the data I needed from the body (server and data base names) to the url of the request. Then I created a POCO for that data that I inject into the ActionFilter and populate with the data from the url. That POCO isntance is now available in every service down the dependency chain that needs it.
For the rest of the data I needed in my SomeData object, I followed approach 1, made WorkerService's constructor parameterless and passed the data like:
_myService.DoSomething(someData);
One final trick was adding the ActionFilter to config.Filters, because my filter has it's own dependencies, I couldn't just do:
config.Filters.add(new MyActionFilter(What_About_The_Parametes_???))
I had to get the structureMap's container instance and have it return a instance of my filter which will the cause all the dependencies to be injected into it, and then I can add the filter instance to config.Filters:
var container = StructuremapMvc.StructureMapDependencyScope.Container;
config.Filters.Add(container.GetInstance<IMyActionFilter>());

Related

ASP.NET Core Middleware and URL Parsing

Trying to add special endpoints to an ASP.NET Core MVC through a middleware.
In a app.UseWhen, I need to parse the request URL. In a Controller context, MVC does a great job extracting userId using the following template:
GET http://contoso.com/users/{userId}/addresses
How could this be cleanly done in a middleware where MVC Controller constructs aren't setup?
Bonus points if the answer helps figuring out if the address conforms to this pattern in the first place.
All I have on hand is a DefaultHttpContext.
Solution based on Mark Vincze's blog
This method used to extract the the user id and work with it...
private static void AddAddressesRoute(IApplicationBuilder app, RouteBuilder builder)
{
builder.MapVerb(
HttpMethod.Get.Method,
"users/{userId}/addresses",
async context =>
{
var routeData = context.GetRouteData();
var userId = routeData.Values["userId"];
// userId available from here
}
);
}
Should be initiated from an application builder extension method.
public static IApplicationBuilder UseAddresses(
this IApplicationBuilder app
)
{
RouteBuilder builder = new RouteBuilder(app);
AddAddressesRoute(app, builder);
app.UseRouter(builder.Build());
return app;
}
Becomes a middleware that can be added to the Startup.Configure method just like this:
app.UseAddresses()
It doesn't even interfere with MVC that still gets triggered if the route doesn't match.
URL parsing comes to play in MVC pipeline, not in ASP.NET Core one.
You might want to consider MVC filters instead, which have access to routing context.
You can access the HttpContext from middleware and parse out key-value pairs from the query string but you can not access the path parameters via key-value.
For example:
You make a GET to the following controller via http://contoso.com/api/users/5?zip=90210:
// GET api/users/5
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return "value";
}
Custom Middleware:
public class MyCustomMiddleware
{
public Task InvokeAsync(HttpContext context)
{
// get full path from context request path
var queryPath = context.Request.Path().ToString();
// will return /api/users/5
// get id from query string
var queryStringId = context.Request.Query["zip"].ToString();
// will return 90210
}
}
There isn't any mapping from your Controller parameters to the HttpContext.

Net Core Dependency Injection for Non-Controller

Seems crazy that something like this is causing me such a headache. But here it is:
How do you use the built-in dependency injection for net core for a non-controller class? Please provide an example with includes instantiation.
Thanks.
Just make the class a service.
In startup.cs
services.AddScoped<AccountBusinessLayer>();
Then in controller, same as you do for other services:
private readonly AccountBusinessLayer _ABL;
Include in constructor as you do for other services:
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,IOptions<IdentityCookieOptions> identityCookieOptions,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory,
RoleManager<IdentityRole> roleManager,
AccountBusinessLayer ABL
)
{
_userManager = userManager;
_signInManager = signInManager;
_externalCookieScheme = identityCookieOptions.Value.ExternalCookieAuthenticationScheme;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
_roleManager = roleManager;
_ABL = ABL;
}
You can easily define a static class with one property like:
public static class StaticServiceProvider
{
public static IServiceProvider Provider { get; set; }
}
after defined class you have to scope the service in the Startup.ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
//TODO: ...
services.AddScoped<IUnitOfWork, HttpUnitOfWork>();
services.AddSingleton<ISomeInterface, ISomeImplementation>();
}
then inside the Startup.Configure method on startup you can set the provider as static class property:
public void Configure(IApplicationBuilder app, ...)
{
StaticServiceProvider.Provider = app.ApplicationServices;
//TODO: ...
}
Now you can easily call StaticServiceProvider.Provider.GetService method almost everywhere in your application:
var unitOfWork = (IUnitOfWork)StaticServiceProvider.Provider.GetService(typeof(IUnitOfWork));
I'm not sure this is the best answer, but the way I decided to do it is to do the following:
1) Per the answer by #BrunoLM at on this question Resolving instances with ASP.NET Core DI suggested by #SystemCrash, I created a new project called UnderstandingDependencyInjection and pasted in the code examples.
Important: What I describe next see next will not make sense unless you visit the referenced link above (#1). What you see below is a partial solution that builds on the answer another user provided in a another SO question.
2) Next, I created another class called OtherService. I added a method DoSomething() that took a dependency on the TestService.
3) In the constructor of OtherService, I requested IServiceProvider in order to get a concrete implementation of ITestService so I could call its GenerateRandom() method.
4) Back in the HomeController.cs, I merely passed along the IServiceProvider reference to the constructor of OtherService.
So, this is what I have:
OtherService.cs
using System;
using Microsoft.Extensions.DependencyInjection;
namespace UnderstandingDependencyInjection.Services
{
public class OtherService
{
private readonly ITestService _testService;
public OtherService(IServiceProvider serviceProvider)
{
_testService = serviceProvider.GetService<ITestService>();
}
public int DoSomething()
{
var rnd = _testService.GenerateRandom();
return rnd * 2;
}
}
}
HomeController.cs
using Microsoft.Extensions.DependencyInjection;
using UnderstandingDependencyInjection.Services;
namespace UnderstandingDependencyInjection.Controllers
{
public class HomeController : Controller
{
private readonly ITestService _testService;
private readonly IServiceProvider _serviceProvider;
public HomeController(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_testService = serviceProvider.GetService<ITestService>();
}
public IActionResult Index()
{
// This works!
// var rnd = _testService.GenerateRandom();
// What if I need to reference the TestService
// from another service? I.e., OtherService?
var otherService = new OtherService(_serviceProvider);
var rnd = otherService.DoSomething();
ViewBag.RandomNumber = rnd;
return View();
}
So, to summarize, the key to this technique is to pass around the concrete reference of IServiceProvider that your controller receives ... passing from the controller into any other custom classes that will also need any services that are registered into ASP.NET Core's DI framework.
What about static methods that depend on the TestService?
But, I may not want / need to create an instance of OtherService. I may want to merely call a method statically, but that method takes a dependency on a service managed by ASP.NET Core MVC's Dependency Injection framework. What now?
In this case, the best I can figure out, you would need to pass in the reference ON THE METHOD CALL to the static method. It looks nasty, and I'm hoping there's a more elegant way ... but here's what I figured out.
5) Building on the previous steps (above) I added a new class called StaticService.
6) I created a method DoSomething that takes IServiceProvider as a parameter.
7) I use the concrete instance of the IServiceProvider to get a concrete instance of the ITestService. I use this to call GenerateRandom().
8) From the controller, call the StaticService.DoSomething() method passing it the concrete instance of IServiceProvider that I'm holding on to.
StaticService.cs
using Microsoft.Extensions.DependencyInjection;
namespace UnderstandingDependencyInjection.Services
{
public class StaticService
{
// No constructors
public static int DoSomething(IServiceProvider serviceProvider)
{
var testService = serviceProvider.GetService<ITestService>();
var rnd = testService.GenerateRandom();
return rnd * 3;
}
}
}
HomeController.cs
public IActionResult Index()
{
// This works!
// var rnd = _testService.GenerateRandom();
// What if I need to reference the TestService
// from another service? I.e., OtherService?
//var otherService = new OtherService(_serviceProvider);
//var rnd = otherService.DoSomething();
// What if I need to reference the TestService
// from another service with a STATIC method?
// Best I can tell, you have to pass the
// ServiceProvider in on the method call.
var rnd = StaticService.DoSomething(_serviceProvider);
ViewBag.RandomNumber = rnd;
return View();
}
But isn't passing around ServiceProvider an anti-pattern?
In short, yes. You wind up passing ServiceProvider around everywhere in code. Some would argue that this gives every controller and ever class access to every service registered in ASP.NET Core's DI. That's true, and that seems bad.
But what are your alternatives? Should every class that has a dependency on your service ALSO be defined as a service and registered with the DI? In other words, should I create IOtherService, and then pass it a concrete ITestService in its constructor?
I could do that, HOWEVER now my controller's constructor needs BOTH ITestService AND IOtherService. In other words, in order to work correctly, the Controller needs to know how OtherService does its job and that it uses ITestService internally. That seems bad, too.
What to do?
What's the Best Answer?
Frankly, I think the best answer is found here:
Passing Services using Dependency Injection and Factory Pattern in ASP.NET
#Steven says in his answer:
It does mean however that you might need to move away from the built-in DI container of ASP.NET Core to a more feature rich DI library, because the built-in container is not capable of making a context aware registration for ILogger while having the library auto-wire other constructor dependencies as well.
There are actually many ways to inject your dependency, the most common one you will find on controllers. There is also this variant
var someService = (ISomeService)HttpContext.RequestServices.GetService(typeof(ISomeService));

Configure Unity container per-request in OWIN middleware

I'm wanting to configure registrations in a Unity container being used by ASP.NET Web API 2 based on properties of a HTTP request. For example, a request to /api/database1/values should result in a Unity container configuration with an IDbContext configured for database1, while a request to /api/database4/values will get an IDbContext configured for database4.
I've gotten so far as using UnityHierarchicalDependencyResolver as the dependency resolver, so types registered with HierarchicalLifetimeManager last only for the lifetime of the request. This works well for getting types resolved per request. But how to get them registered per request using OWIN middleware is beyond me.
In my middleware, a call to System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUnityContainer)) gets an instance of IUnityContainer, but it's the same container for all requests, including any registrations from previous requests.
By encapsulating UnityHierarchicalDependencyResolver with my own implementation of IDependencyResolver I can see that IDependencyResolver.BeginScope isn't called until much later in the process. So the problem would seem to be that the child container isn't created until Web API wakes up, long after my middleware calls Next(..).
Is there a way I can get the scope of my dependency resolver to start sooner? Is there some other strategy that I'm missing. In case it makes any difference, I'm hosting in IIS, but favouring the OWIN middleware approach.
Update
This isn't an answer, and it's too big for a comment, but after struggling to solve this with Unity I decided to switch to Autofac and it all just fell into place.
The Autofac OWIN packages (Autofac.Mvc5.Owin, Autofac.Owin, Autofac.WebApi2.Owin) make it dead easy to use Autofac within the OWIN pipeline and ensure appropriate lifetime management in ASP.NET MVC and Web API. This was the missing link.
I couldn't find a way to reconfigure the container per-request, but it did at least make it possible to configure a factory per-request (so yes, #Haukinger and #alltej, you were right to push in that direction.
So I register a factory like:
builder.RegisterType<DataDependencyFactory>().InstancePerRequest();
And register the create method of that factory like:
builder
.Register(c => c.Resolve<DataDependencyFactory>().CreateDataDependency())
.As<IDataDependency>()
.InstancePerRequest();
Registering the factory this way is particularly useful, because downstream dependents don't need to be aware of the factory. I like this because my dependents don't need a factory, they need an instance. The container bends to the needs of my dependents, not the other way around :)
Then, in a piece of OWIN middleware, I resolve the factory, and set a property on it according to the properties of the request. Subsequent resolution of IDataDependency in an MVC or Web API controller, or anything else later in the OWIN pipeline, will get an instance configured according to the property on the factory.
Based on your api URL ("/api/database4/values"), I suggest that you create a filter attribute(e.g. DbIdFilter) so that you can reuse the filter attribute to other controller methods that follow similar url path/segment like this below:
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/values")]
public IHttpActionResult GetValues()
{
return Ok();
}
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/products")]
public IHttpActionResult GetProducts()
{
return Ok();
}
First, create the filter attribute:
public class DbIdFilterAttribute : ActionFilterAttribute
{
private readonly string _routeDataId;
private const string defaultRouteName = "databaseId";
public DbIdFilterAttribute():this(defaultRouteName)
{}
public DbIdFilterAttribute(string routeDataId)
{
_routeDataId = routeDataId;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
var routeData = actionContext.Request.GetRouteData();
var dbId = routeData.Values[_routeDataId] as string;
//here we create the db instance at the filter level.
DbInstanceFactory.RegisterDbInstance(dbId);
}
}
Next, create an instance factory that will register/resolve the db instance during runtime:
public class DbInstanceFactory : IDbInstanceFactory
{
public static IDbInstance RegisterDbInstance(string databaseId)
{
var factory = UnityConfig.GetConfiguredContainer().Resolve<IDbInstanceFactory>();
return factory.CreateInstance(databaseId);
}
public IDbInstance CreateInstance(string databaseId)
{
var container = UnityConfig.GetConfiguredContainer();
//container.RegisterType<IDbInstance, DbInstance>();
container.RegisterType<IDbInstance, DbInstance>(new InjectionConstructor(databaseId));
var dbInstance = container.Resolve<IDbInstance>();
return dbInstance;
}
public IDbInstance GetInstance()
{
var container = UnityConfig.GetConfiguredContainer();
var dbInstance = container.Resolve<IDbInstance>();
return dbInstance;
}
}
public interface IDbInstanceFactory
{
IDbInstance CreateInstance(string databaseId);
IDbInstance GetInstance();
}
Register this factory class in UnityConfig.cs (or wherever you currently register the types):
container.RegisterType<IDbInstanceFactory, DbInstanceFactory>
(new ContainerControlledLifetimeManager());
It's registered ContainerControlledLifetimeManager since this factory does not have to be a per request.
So just a basic DbInstance class below(for clarity) that takes a parameter in the constructor (this parameter can be your connection string or a named connection):
public class DbInstance : IDbInstance
{
public string DbId { get; }
public DbInstance(string databaseId)
{
DbId = databaseId;
}
}
public interface IDbInstance
{
string DbId { get; }
}
In controller class, you can use it like this:
....
private IDbInstanceFactory _dbFactory;
public MyController(IDbInstanceFactory dbFactory)
{
_dbFactory = dbFactory;
}
// Alternate, if you want to use property injection instead of constructor injection
//[Dependency]
//public IDbInstanceFactory DbFactory { get; set; }
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/test")]
public IHttpActionResult Test()
{
var db = _dbFactory.GetInstance();
return Ok(db.DbId);
}
...

ASP.Net Core Call a controller from another controller

In my ASP.Net Core MVC 6 solution I have two sets of controllers. One set contains the webpages with their regular views. Another set contains the API controllers.
To avoid duplicating db logic the web controllers are using the API controllers. Currently I am creating an instance of the required controller manually by handing it a DbContext as constructor argument. This is the DbContext given to web controller by dependency injection.
But whenever I add another constructor parameter to the API controller I need to modify all web controllers that use this API controller.
How can I use the dependency injection system builtin to ASP.Net 5 to create an instance of the required API controller for me? Then it would fill in the required constructor parameters automatically.
One solution could be to move the db logic from the API controllers to a separate layer and call that from both API and web controllers. This would not solve my problem since the new layer would still need the same parameters and I'm not fan of the unnecessary wiring.
Another solution would be to have the web controllers access the API through a web call, but that just adds complexity to the app.
Today I am doing this:
public IActionResult Index()
{
using (var foobarController = new Areas.Api.Controllers.FoobarController(
// All of these has to be in the constructor of this controller so they can be passed on to the ctor of api controller
_dbContext, _appEnvironment,
_userManager, _roleManager,
_emailSender, _smsSender))
{
var model = new IndexViewModel();
model.Foo = foobarController.List(new FoobarRequest() { Foo = true, Bar = false });
model.Bar = foobarController.List(new FoobarRequest() { Foo = false, Bar = true });
return View(model);
}
}
And I am hoping for something like this:
(This example does not work.)
using (var foobarController = CallContextServiceLocator.Locator.ServiceProvider.GetService<Areas.Api.Controllers.FoobarController>())
{
var model = new IndexViewModel();
model.Foo = foobarController.List(new FoobarRequest() { Foo = true, Bar = false });
model.Bar = foobarController.List(new FoobarRequest() { Foo = false, Bar = true });
return View(model);
}
How can I use the dependency injection system builtin to ASP.Net 5 to create an instance of the required API controller for me?
In your Startup.cs can tell the MVC to register all your controllers as services.
services.AddMvc().AddControllersAsServices();
Then you can simply inject the desired controller in your other controller via the DI mechanism and invoke its action method.
Don't do it. Move that logic to another component that gets shared between the 2 controllers. The controller is dispatched to by the framework as a result of an HTTP call, its not your public API surface. In general, your controllers should be used as a the place where the HTTP request is transformed into business objects. Operations on those objects should be delegate to another layer (especially if it needs to be used from more than one place in your application).
To be able to use a controller from another controller you need to:
Register the controller in Startup.cs ConfigureServices: services.AddTransient <Areas.Api.Controllers.FoobarController, Areas.Api.Controllers.FoobarController>();
You must pass the controller you want to access as a ctor parameter into the main controller.
If you need to access local properties in the controller such as User or Url there are two ways to do this.
The first way is to use DI to get an instance of IHttpContextAccessor to access User and IUrlHelper to access Url objects:
public class FoobarController : Controller
{
private readonly ApplicationDbContext _dbContext;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IUrlHelper _urlHelper;
public FoobarController(ApplicationDbContext dbContext, IHttpContextAccessor httpContextAccessor, IUrlHelper _urlHelper, [...])
{
_dbContext = dbContext;
_httpContextAccessor = httpContextAccessor;
_urlHelper = urlHelper;
}
public FoobarResponse List(FoobarRequest request)
{
var userId = _httpContextAccessor.HttpContext.User.GetUserId();
var response = new FoobarResponse();
response.List = _dbContext.Foobars.Where(f => f.UserId == userId).ToList();
response.Thumb =
return response;
}
}
The second way is to set it in the calling controller:
public class HomeController : Controller
{
private Areas.Api.Controllers.FoobarController _foobarController;
public HomeController(Areas.Api.Controllers.FoobarController foobarController)
{
_foobarController = foobarController;
}
private void InitControllers()
{
// We can't set this at Ctor because we don't have our local copy yet
// Access to Url
_foobarController.Url = Url;
// Access to User
_foobarController.ActionContext = ActionContext;
// For more references see https://github.com/aspnet/Mvc/blob/6.0.0-rc1/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs
// Note: This will change in RC2
}
public IActionResult Index()
{
InitControllers();
var model = new IndexViewModel();
model.Foo = _foobarController.List(new FoobarRequest() { Foo = true, Bar = false });
model.Bar = _foobarController.List(new FoobarRequest() { Foo = false, Bar = true });
return View(model);
}
}
The source code for ASP.Net Core MVC6 RC1 Controller can be found here. It is however undergoing heavy rewrite for RC2 and with it the properties that has to be copied to get access to User and Url will change.
#B12Toaster is correct for MVC but if you only use ApiController you should do it like this:
services.AddControllers().AddControllersAsServices();
Why would your new layer need wiring up? Why not take in an object into both controllers and call a method on that object. The DI container could resolve the dependencies of this new object without duplicated wiring couldn't it?
ie you could have this:
public class MvcController
{
SharedComponent sharedComponent;
public MvcController(SharedComponent sharedComponent)
{
this.sharedComponent = sharedComponent;
}
public IActionResult Index()
{
var model = new IndexViewModel();
model.Foo = shredComponent.List(new FoobarRequest() { Foo = true, Bar = false });
model.Bar = shredComponent.List(new FoobarRequest() { Foo = false, Bar = true });
return View(model);
}
}
//Repeat this for the API controller
public class SharedComponent
{
public SharedComponent(DBContext dbContext, AppEnvironment appEnvironment, UserManager userManager, RoleManager roleManager,
EmailSender emailSender, SmsSender smsSender)
{
...Store in fields for later usage
}
}
I'd have to agree with others that injecting the controller may not be the best route. Mostly because it marries the business logic with ASP.Net instead of treating it like an IO device like, in my opinion, it should be.
Let's say we have an interface that looks like this:
public interface ICalculator {
int Add(int left, int right);
}
and we have an implementation that stores the business logic:
public class MyCalculator : ICalculator {
public int Add(int left, int right) => left + right;
}
This implementation can be used as a background service, within the same process as a WPF application, or as an ASP.NET WebAPI controller. It would look something like this:
[ApiController]
[Route("api/{controller}")]
public void CalculatorController : Controller, ICalculator {
private readonly ICalculator _calculator;
public CalculatorController(ICalculator calc) => _calculator = calc;
[Route("Add")]
public int Add(int left, int right) => _calculator.Add(left, right);
}
If that controller has a dependency on a repository you can inject that interface too. Personally I like defining a collection of repositories (like IUserRepository for example) and injecting only what is needed instead of the entire DbContext.
public CalculatorController(ICalculator calculator, IDbContext db) { }
There's nothing wrong with a controller depending on more than just the thing it is decorating. Just make sure you have a set of tests that assert various things. For example you could assert that when a particular controller method is called the particular method on the other interface is also called.
Personally I find this approach a better fit. It's okay to use certain technologies but they should be kept at arm's length from the business rules. A developer should be able to take the business rules that govern a particular part of the code and switch from a WCF service to ASP.NET WebAPI trivially.
I've personally been a part of a couple projects where we had to switch from one database technology to another (SQL Server to CouchDB) and one where our micro-services needed to be running as restful Web API services instead of Windows services. If you architect things this way those types of projects become relatively trivial compared to how things are normally composed.

How does ASP.NET MVC know what controller constructor to call?

I'm currently starting ASP.NET MVC 4 and in the book I am reading, the author introduced Ninject for dependency injection. He created a custom dependency resolver (which I don't fully understand how it works, but I think it's use is to easily manage dependency resolution).
Here is the controller code:
public class HomeController : Controller
{
private Product[] products = {
new Product {Name = "Kayak", Category = "Watersports", Price = 275M},
new Product {Name = "Lifejacket", Category = "Watersports", Price = 48.95M},
new Product {Name = "Soccer ball", Category = "Soccer", Price = 19.50M},
new Product {Name = "Corner flag", Category = "Soccer", Price = 34.95M}
};
private IValueCalculator calc;
public HomeController(IValueCalculator calcParam)
{
calc = calcParam;
}
public ActionResult Index()
{
ShoppingCart cart = new ShoppingCart(calc) { Products = products };
decimal totalValue = cart.CalculateProductTotal();
return View(totalValue);
}
}
And the custom dependency resolver:
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver()
{
kernel = new StandardKernel();
AddBindings();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
private void AddBindings()
{
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
}
}
In Application_Start(), the resolver was set:
DependencyResolver.SetResolver(new NinjectDependencyResolver());
Questions:
How did ASP.NET MVC knew what controller constructor to call? I assumed it was going to call the default constructor but there isn't one, I tried adding one, still the constructor with the parameter was called.
How did ASP.NET MVC passed the IValueCalculator to the constructor?
This is quote from documentation (https://github.com/ninject/ninject/wiki/Dependency-Injection-With-Ninject):
When asked to instantiate an object, Ninject will look at the type’s
available public constructors and pick the one with the most
parameters it knows how to resolve — or the parameterless one if there
aren’t any suitable ones (there’s an attribute that can be used to
override this – see Constructor injection for the nitty gritty).
and another quote from here (https://github.com/ninject/ninject/wiki/Injection-Patterns):
If a constructor has an [Inject] attribute, it is used (but if you
apply the attribute to more than one, Ninject will throw a
NotSupportedException at runtime upon detection).
If no constructors have an [Inject] attribute, Ninject will select the one with the most parameters that Ninject understands how
to resolve.
If no constructors are defined, Ninject will select the default parameterless constructor (assuming there is one).
And how did ASP.NET MVC passed the IValueCalculator to the constructor?
Whole MVC pipeline uses controller factories to build instance of specific controller. Controller factory uses DependencyResolver inside. That is why dependency resolver is registered at application start:
DependencyResolver.SetResolver(new NinjectDependencyResolver());
As I wrote earlier, Ninject knows how to find correct constructor and uses it to build instance. It finds this constructor:
public HomeController(IValueCalculator calcParam)
Here dependency resolver is used to find implementation of IValueCalculator, which was defined here:
private void AddBindings()
{
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
}
Ninject here tries one again to find constructor for class LinqValueCalculator. If constructor had dependencies, they would be injected using the same mechanism.
How did ASP.NET MVC know...
It knows by asking the DependencyResolver. MVC will call GetService() when a controller must be created.
The default MVC resolver only handles parametersless constructors, but in your case you have assigned your custom resolver, where the GetService() call will be relayed to NInject's IKernel.TryGet(Type).
NInject will then search for the type HomeController and its constructors, and will find the one with the IValueCalculator parameter.
In the AddBindings() method you have instructed NInject to inject LinqValueCalculator every time a IValueCalculator is required, so it does that, instantiates the type using reflection and returns the initialized controller to MVC.

Resources