In Startup:
services.AddTransient<IMyService, MyService>()
Controller method:
[HttpGet]
public JsonResult GetSomething()
{
Helper helper = new Helper(new MyService()); // works but looking better solution
return Ok("");
}
Helper class:
public class Helper
{
private readonly IMyService myService;
public Helper(IMyService myService)
{
this.myService = myService;
}
public Helper()
{
this.myService = ?;
}
}
I want to instantiate Helper class without inject the dependency manually with new MyService().
The MyService() class should be the class in startup.
I also want to place the the Helper class in another assembly.
I see some code with
var service = (IFooService)serviceProvider.GetService(typeof(IMyService));
but i don't know how to get a serviceProvider instance without injecting it to the helper.
Add the helper to the container
services.AddTransient<IMyService, MyService>()
services.AddScoped<Helper>(sp => new Helper(sp.GetRequiredService<IMyService>()));
And explicitly inject it into the controller
public class MyController: Controller {
private readonly Helper helper;
public MyController(Helper helper) {
this.helper = helper;
}
[HttpGet]
public JsonResult GetSomething() {
//...use helper
return Ok("");
}
//...
}
Ideally the helper should be derived from an abstraction as well
public class Helper : IHelper {
private readonly IMyService myService;
public Helper(IMyService myService) {
this.myService = myService;
}
//...
}
And added accordingly to the container
services.AddTransient<IMyService, MyService>()
services.AddScoped<IHelper, Helper>();
to avoid the controller having tight coupling to concretions (implementation concerns).
public class MyController: Controller {
private readonly IHelper helper;
public MyController(IHelper helper) {
this.helper = helper;
}
[HttpGet]
public JsonResult GetSomething() {
//...use helper
return Ok("");
}
//...
}
A way to properly resolve the service via DI:
[HttpGet]
public JsonResult GetSomething([FromServices] IMyService myService)
{
Helper helper = new Helper(myService);
return Ok("");
}
Or you inject it via ctor and use it in the method.
Related
I have a FilterAttribute that has two parameters, one defined in dependency injection and one defined on method of controller as as string
public controller : ControllerBase
{
[MyFilter("Parameter1", FromDependency)]
public ActionResult MyMethod()
{
....
}
}
and the filter
public MyFilter : Attribute
{
MyFilter(string parameter1, context fromDependency)
{
}
}
How can I inject the parameter from dependency injection?
You can implement an IFilterFactory for this purpose. The runtime checks for this interface when creating filters and calls the CreateInstance method that gets an IServiceProvider as a parameter. You can use this provider to create services and inject them into the filter.
The following sample is taken from the docs:
public class ResponseHeaderFilterFactory : Attribute, IFilterFactory
{
public bool IsReusable => false;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) =>
new InternalResponseHeaderFilter();
private class InternalResponseHeaderFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context) =>
context.HttpContext.Response.Headers.Add(
nameof(OnActionExecuting), nameof(InternalResponseHeaderFilter));
public void OnActionExecuted(ActionExecutedContext context) { }
}
}
If you need to both use services from DI and values defined on the attribute, you can use the following approach:
public class ResponseHeaderFilterFactory : Attribute, IFilterFactory
{
private readonly string _attrParam;
public ResponseHeaderFilterFactory(string attrParam)
{
_attrParam = attrParam;
}
public bool IsReusable => false;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
var svc = serviceProvider.GetRequiredService<IMyService>();
return new InternalResponseHeaderFilter(_attrParam, svc);
}
private class InternalResponseHeaderFilter : IActionFilter
{
private readonly string _attrParam;
private readonly IMyService _service;
public InternalResponseHeaderFilter(string attrParam, IMyService service)
{
_attrParam = attrParam;
_service = service;
}
public void OnActionExecuting(ActionExecutingContext context) =>
context.HttpContext.Response.Headers.Add(
nameof(OnActionExecuting), nameof(InternalResponseHeaderFilter));
public void OnActionExecuted(ActionExecutedContext context) { }
}
}
You can then apply the filter like this:
public controller : ControllerBase
{
[ResponseHeaderFilterFactory("Parameter1")]
public ActionResult MyMethod()
{
....
}
}
You can implement ActionFilterAttribute to get DI dependencies from HttpContext.RequestServices:
public sealed class MyAttr : ActionFilterAttribute
{
MyAttr(string parameter1)
{
}
public override void OnActionExecuting(ActionExecutingContext context)
{
//Get dependency from HttpContext services
var myDependency = context.HttpContext.RequestServices.GetService<MyDependency>();
//Use it
myDependency.DoSomething();
//....
}
}
Injecting components into action filter attributes directly is not possible but there are various workarounds to allow us to effectively accomplish the same thing. Using ServiceFilter is a relatively clean way to allow dependency injection into individual action filters.
The ServiceFilter attribute can be used at the action or controller level. Usage is very straightforward:
[ServiceFilter(typeof(MyFilter))]
And our filter:
public class MyFilter: IActionFilter
{
MyFilter(string parameter1, context fromDependency)
{
}
}
Obviously, as we are resolving our filter from the IoC container, we need to register it:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<MyFilter>(x =>
new Service(x.GetRequiredService<IOtherService>(),
"parameter1"));
...
}
more details in Paul Hiles article: here
If I have a controller class, and I want to pass it to a different namespace that handles my HTTP calls, such as in the below scenario, Main task calls TaskA() which calls TaskG(), do I need to pass it to TaskG via A like the below? Or is there someway to just create it in the namespace HttpClassFurtherDown without the calling classes needing to pass it.
namespace Controllers{
public class Drawings : ControllerBase
{
private IHttpClientFactory _client {get;set;}
public Drawings(IHttpClientFactory client)
{
_client=client;
}
[Route("api/Drawings")]
[HttpPost]
public async Task<ActionResult> PostAsync([FromBody] JsonFileContent[] content)
{
HttpExample e = new HttpExample(_client);
e.TaskA();
TaskB();
return Accepted($"Drawings/Job/{id}");
}
}}
namespace HttpClassExample{
public class HttpExample
{
private IHttpClientFactory _client {get;set;}
public HttpExample(IHttpClientFactory client)
{
_client=client;
}
public void TaskA()
{
DoSomeProcessing();
HttpClassExampleFurtherDown e = new HttpClassExampleFurtherDown(client);
e.TaskG();
}
}
}
namespace HttpClassExampleFurtherDown{
public class HttpExampleFurtherDown
{
private IHttpClientFactory _client {get;set;}
public HttpExampleFurtherDown(IHttpClientFactory client)
{
_client=client;
}
public void TaskG(client)
{
//Finally Using It Here. I want to avoid having to generate it at the controller level and pass it all the way down.
client.CreateClient();
client.SendAsync();
}
}
}
I want to avoid having to generate it at the controller level and pass it all the way down.
If following DIP then inject explicit dependencies where they are actually needed instead of tightly coupling to implementation concerns.
While I believe the example provided are oversimplified, here is what the example above should look like
Controllers.Drawings
namespace Controllers{
using HttpClassExample;
//...
public class Drawings : ControllerBase {
private readonly IHttpExample client;
public Drawings(IHttpExample client) {
this.client = client;
}
[Route("api/Drawings")]
[HttpPost]
public async Task<ActionResult> PostAsync([FromBody] JsonFileContent[] content) {
await client.TaskA();
TaskB();
return Accepted($"Drawings/Job/{id}");
}
}
}
HttpClassExample.HttpExample
namespace HttpClassExample{
using HttpClassExampleFurtherDown;
//...
public class HttpExample : IHttpExample{
private readonly IHttpExampleFurtherDown client;
public HttpExample(IHttpExampleFurtherDown client) {
this.client = client;
}
public async Task TaskA() {
DoSomeProcessing();
await client.TaskG();
}
//...
}
}
HttpClassExampleFurtherDown.HttpExampleFurtherDown
namespace HttpClassExampleFurtherDown{
public class HttpExampleFurtherDown : IHttpExampleFurtherDown {
private readonly IHttpClientFactory factory;
public HttpExampleFurtherDown(IHttpClientFactory factory) {
this.factory = factory;
}
public async Task TaskG() {
HttpClient client = factory.CreateClient();
//...
var response = await client.SendAsync();
//...
}
}
}
This assumes that a container is being used to manage the resolution and injection of dependency implementations based on their registered abstractions
Given the following ASP.NET Core controller :
public class MyController : Controller {
public MyController(IDependency dependency) { this.dependency = dependency; }
}
public interface IDependency;
public class DependencyImplementation : IDependency {
public DependencyImplementation(Controller controller) { ... }
}
I want MyController to have a new instance of DependencyImplementation injected, constructed with the controller it's being passed to. Ideally using Ninject.
The non-IoC version would be:
public class MyController : Controller {
public MyController() { this.dependency = new DependencyImplementation(this); }
}
This would cause circular dependency. Only idea I have is to introduce factory:
public interface IDependencyFactory
{
IDependency Create(Controller controller);
}
public class MyController : Controller
{
private IDependency dependency;
public MyController(IDependencyFactory dependencyFactory)
{
this.dependency = dependencyFactory.Create(this);
}
}
var kernel = new StandardKernel();
kernel.Bind<Controller>().To<MyController>();
kernel.Bind<IDependency>().To<DependencyImplementation>();
kernel.Bind<IDependencyFactory>().ToFactory();
var controller = kernel.Get<Controller>();
Or maybe rather reconsider whole design.
I am using Ninject to do some IoC in my ASP.NET MVC application.
I have an interface "IService.cs" :
public interface IService
{
string method();
}
I have the corresponding implementation "Service.cs" :
public class Service
{
string method()
{
return "result";
}
}
I have done the binding in another class heriting from NinjectModule :
public class MyNinjectModule : NinjectModule
{
public override void Load()
{
RegisterServices();
}
private void RegisterServices()
{
Kernel.Bind<IService>().To<Service>();
}
}
I have my class A which use this service :
public class A
{
private readonly IService _service;
private int i;
public A(IService service, int i)
{
this._service=service;
this.i=i;
}
}
The problem is that now, I don't know how to instantiate my class A in my application. This is where am I stuck, how can I call Ninject
to tell my app to go get the implementation of my interface:
var myClass=new A(????)
The main problem is that your Service class does not implement IService.
public class Service
{
string method()
{
return "result";
}
}
It should be
public class Service : IService
{
public string method()
{
return "result";
}
}
But as for instantiating a class, the best approach is to use a composition root to build an object graph. In MVC, that is best handled by implementing IControllerFactory.
public class NinjectControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public NinjectControllerFactory(IKernel kernel)
{
this.kernel = kernel;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return controllerType == null
? null
: (IController)this.kernel.Get(controllerType);
}
}
Usage
using System;
using Ninject;
using DI;
using DI.Ninject;
using DI.Ninject.Modules;
internal class CompositionRoot
{
public static void Compose()
{
// Create the DI container
var container = new StandardKernel();
// Setup configuration of DI
container.Load(new MyNinjectModule());
// Register our ControllerFactory with MVC
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(container));
}
}
In Application_Start, add:
CompositionRoot.Compose();
You will also need to create an interface for your class A and register it. An integer cannot be resolved automatically, you have to do that explicitly.
Kernel.Bind<IClassA>().To<A>()
.WithConstructorArgument("i", 12345);
And then you would add your dependency to a controller. Dependencies of dependencies are resolved automatically.
public class HomeController : Controller
{
private readonly IClassA classA;
public HomeController(IClassA classA)
{
if (classA == null)
throw new ArgumentNullException("classA");
this.classA = classA;
}
public ActionResult Index()
{
// Use this.classA here...
// IService will be automatically injected to it.
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
}
This is what i want to be able to do (passing interface(s) to Controllers):
public class TestController : Controller
{
// GET: Test
[HttpGet]
public ActionResult Index(ITestService service)
{
var test = new TestModel();
test.Greeting = "yo" + service.GetString();
test.Name = "nils";
return View(test);
}
}
This is what i have put in Global.asax.cs in the Application_Start() to try to make that work:
// Create a new Unity dependency injection container
var unity = new UnityContainer();
unity.RegisterType<ITestService,TestService>();
// Finally, override the default dependency resolver with Unity
DependencyResolver.SetResolver(new IoCContainer(unity));
I have also, as you can see, created an IoCContainer class which looks as follows:
public class IoCContainer : IDependencyResolver
{
private readonly IUnityContainer _container;
public IoCContainer(IUnityContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
if (_container.IsRegistered(serviceType))
return _container.Resolve(serviceType);
return null;
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (_container.IsRegistered(serviceType))
return _container.ResolveAll(serviceType);
return new List<object>();
}
public void Dispose()
{
_container.Dispose();
}
}
When i try to access the "http://humptidumptiurl/Test" it tells me:
A public action method 'Login' was not found on controller 'Companyname.Product.Web.Controllers.TestController'.
Now... i thought it should resolve the ITestService.. not bother about a completely different Controller? other controllers that does not use Unity yet, work as they have always done....
Inputs on how i could achieve my desired solution would be greatly appriciated
EDIT:
Thank you! Of course it injects through the constructor... I should have thought of that... but now it gives me this error message:
{"An error occurred when trying to create a controller of type 'Stimline.Xplorer.Web.Controllers.TestController'. Make sure that the controller has a parameterless public constructor."}
Edited testController:
public class TestController : Controller
{
private readonly ITestService _testService;
public TestController(ITestService service)
{
_testService = service;
}
// GET: Test
[HttpGet]
public ActionResult Index()
{
var test = new TestModel();
test.Greeting = "yo" + _testService.GetString();
test.Name = "nils";
return View(test);
}
}
You're injecting your dependency into your action method.
When using IDependencyResolver in this manner you tend to inject dependencies into your constructor.
Try changing controller to look something like this:
public class TestController : Controller
{
private readonly ITestService service;
public TestController(ITestService service)
{
this.service = service;
}
// GET: Test
[HttpGet]
public ActionResult Index()
{
var test = new TestModel();
test.Greeting = "yo";
test.Name = "nils";
// TODO do something with ITestService
// this.service.DoSomethingCool()
return View(test);
}
}
Declare it like this :
public class TestController : Controller
{
private ITestService service;
public TestController(ITestService service)
{
this.service = service;
}
// GET: Test
[HttpGet]
public ActionResult Index()
{
var test = new TestModel();
test.Greeting = "yo";
test.Name = "nils";
return View(test);
}
}
Please inject your dependencies inside your constructor. You by mistake passed it to your action method.