Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dotnet core method injection with controller methods

Lets say i have the following controller in dotnet core:

[Route("api/v1/[controller]")]
public class ValuesController : Controller
{
    private readonly IHandler<ValuesRequest, ValuesResponse> _valueHandler;
    private readonly IHandler<ValuesIdRequest, ValuesIdResponse> _valueIdHandler;

    public ValuesController(IHandler<ValuesRequest, ValuesResponse> valueHandler, 
                            IHandler<ValuesIdRequest, ValuesIdResponse> valueIdHandler)
    {
        _valueHandler = valueHandler;
        _valueIdHandler = valueIdHandler;
    }

    [HttpGet]
    public ValuesResponse Get(ValuesRequest request)
    {
        return _valueHandler.Handle(request);
    }

    [HttpGet("{id}")]
    public ValuesIdResponse Get(ValuesIdRequest request)
    {
        return _valueIdHandler.Handle(request);
    }
}

As you can see in the code above, I'm using dependency injection though the constructor. However, I was thinking on how I could reduce the amount of code. So, I was thinking about using method injection, which should reduce the code to something like this:

[Route("api/v1/[controller]")]
public class ValuesController : Controller
{
    [HttpGet]
    public ValuesResponse Get(ValuesRequest request, IHandler<ValuesRequest, ValuesResponse> handler)
    {
        return handler.Handle(request);
    }

    [HttpGet("{id}")]
    public ValuesIdResponse Get(ValuesIdRequest request, IHandler<ValuesIdRequest, ValuesIdResponse> handler)
    {
        return handler.Handle(request);
    }
}

I was wondering if it is possible to do something like this in combination with controller params. I tried finding an answer on the web, however I could not find similar problem/solution.

like image 483
Gilian Avatar asked Aug 03 '18 11:08

Gilian


People also ask

How do you inject service to a controller?

You can inject it like this, but consider injecting service through your controller constructor. @PostMapping("/api/franchises") public ResponseEntity<Object> createFranchise(CreateFranchiseDTO dto) { CreateFranchiseUseCase useCase = new CreateFranchiseUseCase(); Frachise franchise = useCase. execute(dto); // ... }

How does DI work in .NET Core?

ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. For more information specific to dependency injection within MVC controllers, see Dependency injection into controllers in ASP.NET Core.

What is IServiceCollection in .NET Core?

IServiceCollection is the collection of the service descriptors. We can register our services in this collection with different lifestyles (Transient, scoped, singleton) IServiceProvider is the simple built-in container that is included in ASP.NET Core that supports constructor injection by default.


2 Answers

Reference 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 ValuesResponse Get(ValuesRequest request, [FromServices]IHandler<ValuesRequest, ValuesResponse> handler)
{
    return handler.Handle(request);
}
like image 114
Nkosi Avatar answered Oct 17 '22 13:10

Nkosi


While the answer would work using [FromService] within your actions, I have another suggestion.

From what I understand by reading the code you have provided is, that you use some kind of CQRS. For that case I can suggest MediatR. You will then only need to inject one interface into your controller and send your request using the IMediator. This way you will keep your controller small and clean and you will not need to inject all the other handlers.

There is a nice and handy extension for Microsoft's IoC-Container to register all your handlers and all other necessary classes to use MediatR.

services.AddMediatR(typeof(Startup).Assembly);
like image 4
alsami Avatar answered Oct 17 '22 15:10

alsami