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.
Related
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>());
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));
I'm developing ASP.NET MVC 5 app. I need to use parameters in controller's constructor. DefaultControllerFactory can't resolve it and i inherited from it my own ControllerFactory:
public class ControllerFactoryProvider : DefaultControllerFactory
{
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
string controllerType = string.Empty;
IController controller = null;
// Read Controller Class & Assembly Name from Web.Config
controllerType = ConfigurationManager.AppSettings[controllerName];
if (controllerType == null)
throw new ConfigurationErrorsException("Assembly not configured for controller " + controllerName);
// Create Controller Instance
IDataTransmitter _dataTransmitter = new DataTransmitter();
controller = Activator.CreateInstance(Type.GetType(controllerType), _dataTransmitter) as IController;
return controller;
}
public void ReleaseController(IController controller)
{
//This is a sample implementation
//If pooling is used to write code to return the object to pool
if (controller is IDisposable)
{
(controller as IDisposable).Dispose();
}
controller = null;
}
}
I registered it in Global.asax:
ControllerBuilder.Current.SetControllerFactory(new
ControllerFactoryProvider());
But when i run my app it whatever use DefaultControllerFactory didn't see constructor with parameters.
Where can i have an error?
As I said in the comments, there is no need to override your controller factory. You just need to plug in your preferred dependency injection container.
I haven't had the opportunity to work with every dependency injection containers for .net but I'll try to give an objective answer.
Ninject
To set up Ninject in an asp.net Mvc 5 project is very straight forward.
Installing the nuget package
There's a very handy nuget package called Ninject.MVC5.
You can install it:
Using the manage nuget packages dialogue, or
By running Install-Package Ninject.MVC5 in the package manager console.
After installing Ninject.MVC5 you will see a new file in your solution in App_Start/ called NinjectWebCommon.cs. Here you can see what the contents of that file will end up being.
Wiring up your dependencies
Now that the package is installed you want to register your denpencies using ninject's api.
Let's say you have an IFoo interface and its implementation Foo
public interface IFoo
{
int Bar()
}
public class Foo : IFoo
{
public int Bar()
{
throw new NotImplementedException();
}
}
In your NinjectWebCommon class you're going to tell ninject how to resolve an IFoo interface:
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IFoo>().To<Foo>();
}
Keep in mind that by default Ninject has implicit self binding of concrete types, that means that
If the type you’re resolving is a concrete type (like Foo above), Ninject will automatically create a default association via a mechanism called implicit self binding. It’s as if there’s a registration like this:
Bind<Foo>().To<Foo>();
I have setup RavenDB embedded in my MVC application. I follower all the tutorials to make the RavenController and I can query the Session in the controller.
Now I would really like to break away from mixing data in the controller and create a Data layer so that I can do some Business logic which will help me create complex View Models.
How do I query the Session in a plain class file? I can't seem to find any info on how to do this.
Dependency Injection is great for this. You move aside the creation of the necessary services and let the container manage the lifecycle of the components, including scoping IDocumentSession to one instance per HTTP request.
As an example, using Autofac (you'd need both the Autofac and Autofac.Mvc5 packages) you could have a class in your App_Start folder like this, and then call AutofacConfig.Configure() from your Global.asax:
public static class AutofacConfig
{
public static IContainer Container { get; private set; }
public static void Configure()
{
var builder = new ContainerBuilder();
var thisAssembly = Assembly.GetExecutingAssembly();
// Register our controllers with the container
builder.RegisterControllers(thisAssembly).PropertiesAutowired(PropertyWiringOptions.PreserveSetValues);
// Provide injections of the HTTP abstractions (HttpContextBase, etc.)
builder.RegisterModule(new AutofacWebTypesModule());
// Create and register the Raven IDocumentStore
builder.Register(c =>
{
var store = new DocumentStore {ConnectionStringName = "RavenDB"};
store.Initialize();
Raven.Client.Indexes.IndexCreation.CreateIndexes(typeof (MvcApplication).Assembly, store);
return store;
})
.As<IDocumentStore>()
.SingleInstance();
// Provide injection of Raven IDocumentSession
builder.Register(c => c.Resolve<IDocumentStore>().OpenSession())
.InstancePerRequest();
Container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(Container));
}
}
Then, when you need an IDocumentSession some place outside of a controller:
// Business logic, or other class that injection is not provided for.
var session = AutofacConfig.Container.Resolve<IDocumentSession>();
Also include autofac otherwise you will get an error saying "does not contain definition Resolve ..."
using Autofac;
You can do similar things with most other DI container libraries; the API is just slightly different.
HttpContext.Current.Session holds current session, but you should definitely not use it in business logic layer. Business logic layer should not be aware of HttpContext.
Basic solution to this problem would be to create interface:
public interface ISession
{
int SomeValue { get; set; }
}
and implementation
public class HttpContextBasedSession : ISession
{
public int SomeValue
{
get
{
return Convert.ToInt32(HttpContext.Current.Session["SomeValue"]);
}
set
{
HttpContext.Current.Session["SomeValue"] = value;
}
}
}
Bind it with dependency injection framework.
I am following "ASP.Net MVC 3" by Steven Sanderson and Adam Freeman, and at one point they define ControllerFactory. The exposed interface is for creating controllers, and what is injected into them (like classes providing data) is black box (for outside world).
I am at the point, that I don't really want to get any controller, but the binding set for controller -- namely class providing data.
I could add another method for controller factory (like GetBinding) and it would work, but would it be the right way to do it?
Just to focus on something. I have IDataProvider and two classes -- MockupProvider and ProviderForReal. I would like to set it once, that for now whenever I need IDataProvider I will get MockupProvider. This is set up (by me) in controller factory.
And I would like to retrieve what I set up in most elegant way, so I won't bind again interface-class again. Is adding such method -- GetBinding -- to controller factor a good pattern?
I am not constructing the controller, I need binding controllers use.
In other words...
There is controller factory. Inside there are defined some bindings. I have to use retrieve them (binding, not controller). Technically I could do this in several ways:
take a look at the code, look at specific binding, and use the the bound type (hardcoding it) somewhere else
add public method to controller factory GetBinding
...?
What is the right way?
Update
My controller factory:
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel ninject_kernel;
public NinjectControllerFactory()
{
ninject_kernel = new StandardKernel();
AddBindings();
}
private void AddBindings()
{
ninject_kernel.Bind<IBookRepository>().To<DataManagement.Concrete.EFBookRepository>();
// ninject_kernel.Bind<IBookRepository>().ToConstant(DataManagement.Mocks.Mocks.BookRepository);
}
public T GetBinding<T>()
{
return ninject_kernel.Get<T>();
}
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
return null;
else
return (IController)ninject_kernel.Get(controllerType);
}
}
I'm trying to answer your questions following the comments. If it won't be suitable for you I'm prepared to delete it.
So in my ASP.NET MVC applications I'm using ninject and its mvc extension to inject dependencies to my controllers (and underlying services and repositories).
Global.asax
public class MvcApplication : Ninject.Web.Mvc.NinjectHttpApplication
{
/// this is here only to see that NinjectHttpApplication uses its own ControllerFactory, which is supposed to create your controllers with dependencies injected
protected override Ninject.Web.Mvc.NinjectControllerFactory CreateControllerFactory()
{
return base.CreateControllerFactory();
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
// here you can configure your bindings according to actual requirements
kernel.Bind<IDataProvider>().To<ProviderForReal>().InRequestScope();
kernel.Bind<IDataService>().To<RealDataService().InRequestScope();
return kernel;
}
}
Controller
public class MyController : Controller
{
private readonly IDataProvider dataService;
// i will get injected an IDataProvider according to my actual configuration
public MyController(IDataService dataService)
{
this.dataService = dataService;
}
}
IDataService
public class RealDataService: IDataService{
private readonly IDataProvider dataProvider;
public RealDataService(IDataProvider dataProvider){
this.dataProvider = dataProvider;
}
}
Update
You do not need to write your own controller factory. In the code above I have put my override of CreateControllerFactory method only to show that Ninject.Web.Mvc.NinjectHttpApplication implicitly overrides this method and uses its own NinjectControllerFactory implmentation which will resolve dependencies for you (even if that dependencies are indirect - as you can see in my updated code => Ninject will resolve it for you because it will see that MyController needs IDataService and will look into bindings and will see that there is binding to RealDataService, but it has only constructor with dependency on IDataProvider. So it will look again to bindings and will see that IDataProvider is bound to ProviderForReal than it will create ProviderForReal inject it to ReadDataService and than RealDataService to MyController).