Dotnet core method injection with controller methods - c#

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.

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

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

Related

ASP.Net Core 2.2 - Method overload appears in Visual Studio but does not work at run-time

I am attempting to verify that a user is authorized via a custom policy. I followed the tutorial at Ode To Code to add this functionality to my controller. From within Visual Studio, the code appears to be correct and utilizing a known overload.
Notice that it says that the overload is an "extension". I didn't take much notice of this until I spent 5 hours today trying to solve the following error:
As you can see, it would appear that the overload I'm attempting to use isn't being utilized. Am I doing something wrong here? Is there something special I have to do to include these extended methods? I've attempted cleaning and rebuilding the solution but this hasn't solved the problem.
While you've defined the field for IAuthorizationSerivce, you haven't provided any way for that to be set. You need to define a constructor for the LRController that takes a single parameter of IAuthorizationService, and assign that to the field.
I think there was a definition of that constructor in the tutorial.
Please note the name change: such as the global variable name for IAuthorizationService _authorization has been prefixed with an underscore. Obviously not required, but as a good rule of thumb/good coding standard, IMO. :-)
public class LRController : Controller
{
private readonly IAuthorizationService _authorization;
// you're missing this constructor & this pattern is known as Constructor Dependency Injection
public LRController(IAuthorizationService authorization)
{
_authorization = authorization;
}
public async Task<RedirectToActionResult> Index()
{
var superAdmin = await _authorization.AuthorizeAsync(User, "IsLucky");
//rest of your code here
}
}
EDIT
Additionally, if you wanted/needed to inject other interfaces into this controller, you would add it to that LRController constructor. Would look something like this:
public class LRController : Controller
{
private readonly IAuthorizationService _authorization;
private readonly IOtherService _otherService;
public LRController(IAuthorizationService authorization, IOtherService otherService)
{
_authorization = authorization;
_otherService = otherService;
}
public async Task<RedirectToActionResult> Index()
{
var superAdmin = await _authorization.AuthorizeAsync(User, "IsLucky");
}
public async Task Foo()
{
await _otherService.Bar();
}
}

Conditional binding in WebApi2 controller method

I am using Ninject with the following packages:
Ninject
Ninject.MVC5
Ninject.Web.Common (and Common.WebHost)
Ninject.Web.WebApi (and WebApi.WebHost)
I have a WebApi2 Controller that looks like the below. My Get() method must be performant and it doesn't depend on the value of IMyFooService, thus I don't care if it gets injected or not when Get() is requested.
Question:
Is there a way for me to selectively bind interfaces only if certain api methods are called? Whether through using attributes or...?
public class FooController : ApiController {
public IMyFooService fooService;
public FooController(IMyFooService fooService) {
this.fooService = fooService;
}
[NonDependent] // Don't really care about the value of fooService
public JsonResult Get() {}
[Dependent] // Must have valid dependency injection
public async Task<JsonResult> Post([FromBody] IList foos) {
var didMyFoo = this.fooService.DoTheFoo();
}
}
Here is my NinjectWebCommon.cs:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IMyFooService>().To<MyConcreteService>().InRequestScope();
}
I noticed that To<T>() has many .When() options. Perhaps I can make use of this to say .When(/* Controller = Foo, Action = Post */).
The easiest, and probably most succinct, way is to use Lazy<T> which was made exactly for this use case - quoting from the docs:
Use lazy initialization to defer the creation of a large or
resource-intensive object, or the execution of a resource-intensive
task, particularly when such creation or execution might not occur
during the lifetime of the program.
Support for Lazy<T> injection comes with Ninject.Extensions.Factory (also see it's Wiki Page on Lazy<T>). Install it's nuget package and you should be ready to inject Lazy<T>.
Adapt the code of your controller as follows:
public class FooController : ApiController {
public Lazy<IMyFooService> fooService;
public FooController(Lazy<IMyFooService> fooService) {
this.fooService = fooService;
}
public JsonResult Get() {}
public async Task<JsonResult> Post([FromBody] IList foos) {
var didMyFoo = this.fooService.Value.DoTheFoo();
}
}
Please notice that the actual service is accessed by the .Value Property on Lazy<T>. On first access to this property the instance is retrieved.
Similar question has been asked some time ago. Check this out. So for you particular case you can just modify IsRouteValueDefined method (you can think about some better naming, I would suggest something like IsRoutePoitingTo) from original answer to something like this (you might revisit if that works for WebApi, but for sure there is a way to get current route for that as well):
public static bool IsRouteValueDefined(string controller, string action)
{
var mvcHanlder = (MvcHandler)HttpContext.Current.Handler;
var routeValues = mvcHanlder.RequestContext.RouteData.Values;
var containsRouteKey = routeValues.ContainsKey(routeKey);
if (routeValue == null)
return containsRouteKey;
return containsRouteKey &&
routeValues["controller"].ToString().Equals(controller, StringComparison.InvariantCultureIgnoreCase) &&
routeValues["action"].ToString().Equals(action, StringComparison.InvariantCultureIgnoreCase);
}
And binding will look like:
kernel.Bind<IMyFooService>()
.To<MyConcreteService>()
.When(x=> IsRouteValueDefined("foo", "get"));
Just not sure about "get" as for ApiController the actual route could be http://website.com/foo/, if so, simply use string.Empty as "action" param. You can check that with your particular project. As you don't need default injection (which is present in original answer) - I just dropped that.

How do you avoid lots of [FromService] parameters with ASP.NET Core dependency injection?

I have an ASP.NET Core project that uses lots of dependency injection.
The problem is that these start to stack up on my controller actions:
public async Task LoginAsync(
[FromBody] LoginModel login,
[FromServices] IConnectionMultiplexer redis,
[FromServices] ISerialiserFactory serialiser,
[FromServices] IDataService dataService,
[FromServices] ILookupNormalizer normaliser,
[FromServices] IPasswordHasher hasher,
...
I can put these in the constructor, but most methods don't use them and those that do don't always use all of them.
I can directly instantiate them, but then I lose the ability to inject them in the startup.
Is there an easier way to get at these injected services? Ideally I want to call something like:
// It turns out I need the injected serialiser
var serialiser = services.Get<ISerialiserFactory>();
Is there a way to do this already in ASP.NET Core?
As pointed in the comments, if you have so many dependencies in a single controller action it, its a very good sigh of badly abstracted code: Your controller is doing more than it should.
Ideally, the controller action should be just a few lines of code per action (rule of thumb, 10-15 lines of code). If you have more, you are probably doing to much inside it.
A controller action should only accept the input from user (form or WebApi-esque), validate it and delegate it to a service as well as handling http status codes.
i.e.
public class LoginService : ILoginService
{
public IConnectionMultiplexer redis,
public ISerialiserFactory serialiser,
public IDataService dataService,
public ILookupNormalizer normaliser,
public IPasswordHasher hasher
public LoginService(/* inject your services here */)
{
}
public async Task<bool> Login(LoginModel login)
{
// Do your logic here and perform the login
return /*true or false*/;
}
}
Then inject this into your controller or your action:
[HttpPost]
public async Task<IActionResult> LoginAsync([FromBody]LoginModel login, [FromServices]ILoginService loginService)
{
// Validate input, only rough validation. No business validation here
if(!Model.IsValid)
{
return BadRequest(Model);
}
bool success = await loginService.Login(model);
if(success)
{
return RedirectTo("Login");
}
return Unauthorized();
}
If you get more code than that, it's a code smell. Especially if you do some logic etc. Your controllers should be as thin as possible. Controllers are rather hard to test (compared to ILoginService in my example).
You should never have to call new LoginService(...) at any time (except, if you create an abstract factory).
Also you should always prefer to use constructor injection. Use [FromServices] only, when the services is required in one single action. If its required in multiple actions, always use constructor injection
public LoginController : Controller
{
public ILoginService loginService;
public LoginController(ILoginService loginService)
{
if(loginService==null)
throw new ArgumentNullException(nameof(loginService));
this.loginService = loginService
}
public async Task<IActionResult> LoginAsync([FromBody]LoginModel login)
{
// Do your stuff from above
...
bool success = await loginService.Login(login);
...
}
}
It's also no problem, if the dependencies have different lifetimes, as long as the lifetime of the main object is shorter than of it's dependencies.
i.e. if your one of the above dependencies is scoped, then your ILoginService must be scoped too. It will be disposed at the end of the request.
services.AddSingleton<ISerialiserFactory, ...>();
services.AddSingleton<IConnectionMultiplexer, ...>();
services.AddScoped<IDataService, ...>();
services.AddScoped<ILookupNormalizer, ...>();
services.AddScoped<IPasswordHasher, ...>();
services.AddScoped<ILoginService, LoginService>();
That will work fine.
services.AddSingleton<ISerialiserFactory, ...>();
services.AddSingleton<IConnectionMultiplexer, ...>();
services.AddScoped<IDataService, ...>();
services.AddScoped<ILookupNormalizer, ...>();
services.AddScoped<IPasswordHasher, ...>();
// This will create trouble
services.AddSingleton<ILoginService, LoginService>();
But this won't. Now, ILoginService will be singleton, but it's dependencies will get disposed after the first request. Subsequent request will triggern an exception when calling IDataService or IPasswordHasher... "xyz has been disposed.".

How to register Drum.UriMaker<> using Simple Injector?

I'm using Drum which provides a generic class `UriMaker:
public class UriMaker<TController>
{
// I need use this one
public UriMaker(UriMakerContext context, HttpRequestMessage request) { }
public UriMaker(Func<MethodInfo, RouteEntry> mapper, UrlHelper urlHelper) { }
}
Used like this:
public class UserController : ApiController
{
public UserController(UriMaker<UserController> urlMaker) {}
}
I've used to register it with Unity:
container.RegisterType(typeof(UriMaker<>),
new InjectionConstructor(typeof(UriMakerContext), typeof(HttpRequestMessage)));
but now migrating to Simple Injector. I already have this:
UriMakerContext uriMaker = config.MapHttpAttributeRoutesAndUseUriMaker();
container.RegisterSingle(uriMakerContext);
So how now register UriMaker<> itself?
Although it is possible to configure Simple Injector to allow injecting an UriMaker<TController> directly into your controllers, I strongly advice against this for multiple reasons.
First of all, you should strive to minimize the dependencies your application takes on external libraries. This can easily be done by defining an application specific abstraction (conforming the ISP).
Second, injecting the UriMaker directly makes your extremely hard to test, since the UriMaker is pulled into your test code, while it assumes an active HTTP request and assumes the Web API route system to be configured correctly. These are all things you don't want your test code to be dependent upon.
Last, it makes verifying the object graph harder, since the UriMaker depends on an HttpRequestMessage, which is a runtime value. In general, runtime values should not be injected into the constructors of your services. You should build up your object graph with components (the stuff that contains the application's behavior) and you send runtime data through the object graph after construction.
So instead, I suggest the following abstraction:
public interface IUrlProvider
{
Uri UriFor<TController>(Expression<Action<TController>> action);
}
Now your controllers can depend on this IUrlProvider instead of depending on an external library:
public class UserController : ApiController
{
private readonly IUrlProvider urlProvider;
public UserController(IUrlProvider urlProvider)
{
this.urlProvider = urlProvider;
}
public string Get()
{
this.urlProvider.UriFor<HomeController>(c => c.SomeFancyAction());
}
}
Under the covers you of course still need to call Drum, and for this you need to define a proxy implementation for IUrlProvider:
public class DrumUrlProvider : IUrlProvider
{
private readonly UriMakerContext context;
private readonly Func<HttpRequestMessage> messageProvider;
public DrumUrlProvider(UriMakerContext context,
Func<HttpRequestMessage> messageProvider)
{
this.context = context;
this.messageProvider= messageProvider;
}
public Uri UriFor<TController>(Expression<Action<TController>> action)
{
HttpRequestMessage message = this.messageProvider.Invoke();
var maker = new UriMaker<TController>(this.context, message);
return maker.UriFor(action);
}
}
This implementation can be registered as singleton in the following way:
container.EnableHttpRequestMessageTracking(config);
UriMakerContext uriMakerContext =
config.MapHttpAttributeRoutesAndUseUriMaker();
IUrlProvider drumProvider = new DrumUrlProvider(uriMakerContext,
() => container.GetCurrentHttpRequestMessage());
container.RegisterSingle<IUrlProvider>(drumProvider);
This example uses the Simple Injector Web API integration package to allow retrieving the current request's HttpRequestMessage using the EnableHttpRequestMessageTracking and GetCurrentHttpRequestMessage extension methods as explained here.

How to move validation handling from a controller action to a decorator

Maintenance Edit
After using this approach for a while I found myself only adding the exact same boilerplate code in every controller so I decided to do some reflection magic. In the meantime I ditched using MVC for my views - Razor is just so tedious and ugly - so I basically use my handlers as a JSON backend. The approach I currently use is to decorate my queries/commands with a Route attribute that is located in some common assembly like this:
[Route("items/add", RouteMethod.Post)]
public class AddItemCommand { public Guid Id { get; set; } }
[Route("items", RouteMethod.Get)]
public class GetItemsQuery : IQuery<GetItemsResponse> { }
// The response inherits from a base type that handles
// validation messages and the like
public class GetItemsResponse : ServiceResponse { }
I then implemented an MVC host that extracts the annotated commands/queries and generates the controllers and handlers for me at startup time. With this my application logic is finally free of MVC cruft. The query responses are also automatically populated with validation messages. My MVC applications now all look like this:
+ MvcApp
+- Global.asax
+- Global.asax.cs - Startup the host and done
+- Web.config
After realizing I really don't use MVC outside the host - and constantly having issues with the bazillion dependencies the framework has - I implemented another host based on NServiceKit. Nothing had to be changed in my application logic and the dependencies are down to System.Web, NServiceKit and NServiceKit.Text that takes good care of the model binding. I know it's a very similar approach to how NServiceKit/ServiceStack does their stuff but I'm now totally decoupled from the web framework in use so in case a better one comes along I just implement another host and that's it.
The situation
I'm currently working on an ASP.NET MVC site that's implementing the businesslogic-view separation via the IQueryHandler and ICommandHandler abstractions (using the almighty SimpleInjector for dependency injection).
The Problem
I've got to attach some custom validation logic to a QueryHandler via a decorator and that's working pretty well in and of itself. The problem is that in the event of validation errors I want to be able to show the same view that the action would have returned but with information on the validation error of course. Here is a sample for my case:
public class HomeController : Controller
{
private readonly IQueryHandler<SomeQuery, SomeTransport> queryHandler;
public ActionResult Index()
{
try
{
var dto = this.queryHandler.Handle(new SomeQuery { /* ... */ });
// Doing something awesome with the data ...
return this.View(new HomeViewModel());
}
catch (ValidationException exception)
{
this.ModelState.AddModelErrors(exception);
return this.View(new HomeViewModel());
}
}
}
In this scenario I have some business logic that's handled by the queryHandler that is decorated with a ValidationQueryHandlerDecorator that throws ValidationExceptions when it is appropriate.
What I want it to do
What I want is something along the lines of:
public class HomeController : Controller
{
private readonly IQueryHandler<SomeQuery, SomeTransport> queryHandler;
public ActionResult Index()
{
var dto = this.queryHandler.Handle(new SomeQuery { /* ... */ });
// Doing something awesome with the data ...
// There is a catch-all in place for unexpected exceptions but
// for ValidationExceptions I want to do essentially the same
// view instantiation but with the model errors attached
return this.View(new HomeViewModel());
}
}
I've been thinking about a special ValidationErrorHandlerAttribute but then I'm losing the context and I can't really return the proper view. The same goes with the approach where I just wrap the IQueryHandler<,> with a decorator... I've seen some strange pieces of code that did some string sniffing on the route and then instantiating a new controller and viewmodel via Activator.CreateInstance - that doesn't seem like a good idea.
So I'm wondering whether there is a nice way to do this ... maybe I just don't see the wood from the trees. Thanks!
I don't think there's a way to make the action method oblivious to this, since the action method is in control of the returned view model, and in case of a validation exception you need to return a view model with all the actual data (to prevent the user from losing his changes). What you might be able to do however to make this more convenient is add an extension method for executing queries in an action:
public ActionResult Index()
{
var result = this.queryHandler.ValidatedHandle(this.ModelState, new SomeQuery { });
if (result.IsValid) {
return this.View(new HomeViewModel(result.Data));
}
else
{
return this.View(new HomeViewModel());
}
}
The ValidatedHandle extension method could look like this:
public static ValidatedResult<TResult> ValidatedHandle<TQuery, TResult>(
this IQueryHandler<TQuery, TResult> handler,
TQuery query, ModelStateDictionary modelState)
{
try
{
return new ValidatedResult<TResult>.CreateValid(handler.Handle(query));
}
catch (ValidationException ex)
{
modelState.AddModelErrors(ex);
return ValidatedResult<TResult>.Invalid;
}
}
Do note that you should only catch such validation exception if the validation is on data that the user has entered. If you send a query with parameters that are set programmatically, a validation exception simply means a programming error and you should blog up, log the exception and show a friendly error page to the user.

Categories

Resources