I've seen tons of articles saying that I must use dependency injection in my Druapl8 controllers that extends ControllerBase (implementing "create" function etc...)
However, ControllerBase allready has protected properties for getting common services such as entityTypeManager, etc. directly from the container.
So, can I use $this->entityTypeManager() directly inside a such a controller or do I have to do the whole stuff ("create" funciton etc...) ?
Thanks
Yes you can use some handy function currentUser(), config() and state() amongst others directly inside controller. Downside is it make unit testing harder.
Related
Recently i tried to create a MVC application using ASP.NET Core 2.0 and i had some values defined in appsettings.json,
"MySettings": {
"WebApiBaseUrl": "http://localhost:6846/api/"
}
In order to read these values i have added
services.Configure<MySettingsModel>(Configuration.GetSection("MySettings"));
above line in ConfigureServices method in Startup.cs
and in my home controller i have added
private readonly IOptions<MySettingsModel> appSettings;
public HomeController(IOptions<MySettingsModel> app)
{
appSettings = app;
}
MySettingsModel class is just a model with property same as key define in appsettings.json.
by this method i'm able to read the value of this key.
Now my issue is that i want to use this key in many controllers so i don't want to repeat this code in every controller so what i did was i created a BaseConntroller, added its constructor and i got my values there. But when i inherit other controllers with my BaseController , it throws me an error and tells me to generate it's constructor, so basically it tells me to add constructor in every controller which is what i wanted to avoid.
How can i achieve this?
You can see the image for the error
And these are the potential fixes that it shows me.
This is just basic C# inheritance. Derived classes must re-implement constructors on base classes (at least the ones you want or need). The only exception is the empty constructor, which is implicit. In other words, you simply need:
public class HomeController : BaseController
{
public HomeController(IOptions<MySettingsModel> app)
: base(app)
{
}
And, of course, you need to change the accessibility of the base class field to protected instead of private. Otherwise, derived classes will not be able to access it.
Of course, this doesn't really save you that much. However, there's no free lunch here. Like I said, this is a limitation of C#, itself, so you have no choice. Although, it's worth mentioning, that while this can sometimes be annoying, it's actually a kind of useful feature of C#. You can look at any class and see exactly what constructors it has available, without having to trace down all its ancestors.
Actually, there is a good solution here:
https://stackoverflow.com/a/48886242/2060975
I am mostly using this method.
[Authorize]
[ApiController]
public abstract class ApiControllerBase : ControllerBase
{
private IOptions<AppSettings> _appSettings;
protected IOptions<AppSettings> appSettings => _appSettings ?? (_appSettings = (IOptions<AppSettings>)this.HttpContext.RequestServices.GetService(typeof(IOptions<AppSettings>)));
...
}
I hope it helps someone:)
I have a middleware library I intend on using in multiple projects. The middleware itself looks something like:
public SdkMiddleware(RequestDelegate next, ILogger<SdkMiddleware> logger, ISdk sdk)
{
this.next = next;
this.logger = logger;
this.sdk = agentSdk;
this.sdk.Init();
...
}
Thanks to DI, I can simply inject my logger:
// Would rather this class be internal...
public class Sdk: ISdk
{
private ILogger<Sdk> logger;
public Sdk(ILogger<Sdk> logger)
{
this.logger = logger;
}
public void Init() {
this.logger.Info(...) // Do some logging
}
The downside to this is my class needs to be registered in every ASP.Net project's Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ISdk, Sdk>();
Is the best/only route? Every time I want to inject a logger into a class, I need to register that class for DI in my composition root?
There is nothing wrong in having the consumer of your library compose the dependencies for this library in the composition root. That's how dependency injection works. You could of course provide some default implementations and a custom extension method that would register those default implementations into the DI and then let the consumer simply call your extension method.
There are a few things that I feel need clarification here:
Dependency injection/inversion of control
To understand what is the benefit of dependency injection(DI) it is better to look at the principle of inversion of control(IoT) that DI implements.
In your case you want SdkMiddleware class to contain a reference to ILogger implementation. The simplest way to do this is for SdkMiddleware class to create an instance of a class that implements ILogger interface. The downside of such approach is that SdkMiddleware needs to know which class implements ILogger interface and how to instantiate it. In other words, SdkMiddleware has control over the creation of ILogger object. The inversion of control happens when the responsibility of knowing which class implements ILogger and how to create an instance of it is taken away from SdkMiddleware to some other class (dependency container in DI) and the instance if it is given to SdkMiddleware to use (through injection in DI). In this case the control over the creation of ILogger object is outside of SdkMiddleware. Since this changes the direction of control, it is called "Inversion of control".
The benefit of this approach is when you will need to provide another implementation of ILogger or change the way you create an instance of that class, you don't need to change SdkMiddleware at all.
Bootstrapping
So now that we clarified why we are using DI, lets take a look at what do we need to actually use it.
The object that creates all instances, controls which object is injected into which and gives away ready to use objects is usually called DI container or IoT container. In asp.net core "IServiceCollection services" is used as such a container. But it still needs to know how to create objects and which implementation to inject for which interface. This is where bootstrapping comes in.
In a bootstrapper class or method you need to specify how objects are built from classes and how classes relate to interfaces. As an example of the former, imagine that you need to pass a connection string for a database from your configuration to a class that creates a db connection. As for the latter, that is exactly what your line "services.AddTransient()" does.
The answer
I am sorry it took so long to get to the actual answer for your question but I wanted to provide some overview first.
Do you need to specify a relation between a class and an interface to inject logger into your class? No. Your class may not even have an interface to begin with and DI container will inject all the dependencies in it by default if you ask for an object of a class instead of an instance of an interface. You can also use or define some convention over configuration solution so that binding of classes and interfaces will happen automatically.
The bottom line is that registration of a class and the actual injection are not connected. But the code you provided is the default way to do this.
I have implemented IAuthenticationFilter to create a custom one. in the constructor I use structureMap to get instance of my IUnitOfWork. this authentication logic is to check user status in the database and ....
IUnitOfWork uow;
public CustomAuthenticatationAttribute()
{
this.uow = ObjectFactory.GetInstance<IUnitOfWork>();
}
I have configured structureMap to serve IUnitOfWork HttpContextScoped.
x.For<IUnitOfWork>().HttpContextScoped().Use(() => new MyDbContext());
but then something strange happened. I deleted the user in one action, but when the AuthenticationFilter is executed on another action, the instance of unitOfWork still returns the user ! I searched the web for hours and I come to this :
Are ActionFilterAttributes reused across threads? How does that work?
in short , it says that Filters are cached and used across requests !
Now I'm confused . how to deal with this ? shall I give up using unitOfWork and get back to using(var context = ....) ? or there is a correct way of using unitOfWork inside Filters .
I found a solution here
https://gist.github.com/ivanra/9019273
It replaces the DefaultFilterProvider and I prefer to avoid that if possible.
The solution you found with suppressing caching in the FilterProvider is actually the same solution that the MVC integration libraries for both Autofac and Simple Injector use.
But the caching behavior of attributes is just one of the many reasons why doing dependency injection in attributes is actually a bad idea.
The best solution is IMO to move to passive attributes if you can, or at least encapsulate the attributes logic and its dependencies into a component and don't do anything more than resolving and executing that component in the OnActionExecuting method. For instance:
public class CustomAuthenticatationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var action =
ObjectFactory.GetInstance<IActionFilter<CustomAuthenticatationAttribute>>();
action.OnActionExecuting(this, context);
}
}
In my ASP.NET Web API controller, I want to restrict access to those in the User role. The common way to do this is to extend the AuthorizeAttribute (example, example) and then sprinkle my controllers with my custom attribute (e.g. [AuthorizeUser]).
Another way to do this is to add a function in the controller's constructor. The constructor is required anyway because I'm using dependency injection.
Here's some code:
public class MyController: ApiController
{
private IUnitOfWork unitOfWork;
private IAccountUtils accountUtils;
// Constructor
public MyController(
IUnitOfWork unitOfWork,
IAccountUtils accountUtils)
{
this.unitOfWork = unitOfWork;
this.accountUtils = accountUtils;
// Restrict access to 'User' role
accountUtils.ThrowExceptionIfUserNotInRole(User.Identity, "User");
}
// More code
}
Because there are countless tutorial and examples of using a filter to authorize users I assumed that was the best way to go. However, when I stepped through my code in the debugger I found that the constructor method gets fired BEFORE the filter.
To optimize code, it makes sense to break as soon as possible if the user is not authorized to access the controller. If I'm not mistaken, then, it should be more efficient to perform authorization in the constructors instead of in a filter. Am I correct or am I missing something here?
It seems like your main concern is optimizing your code, and you're correct to note that the controller constructor runs before the authorization filter. But the difference in performance between those two solutions is extremely small and shouldn't really impact your service.
While throwing from a constructor might work, it's not the most elegant solution because it requires you to authorize in code rather than declaratively with an attribute. It also forces you to mix object instantiation logic with authorization logic which isn't as clean.
So I'd recommend just sticking to using an authorization filter for this one.
I am trying to get Ninject working with a WebForms application that already has a custom PageBase object. But, I don't know for sure if I can use Ninject's PageBase object alongside another, custom PageBase. I've been searching for a while now to see if I could find an answer to this problem, or to learn how to do it, but all I've found is this:
I've hacked together an alternative using a shared base class that
derives from Page. It looks roughly like this
public abstract class PageBase : Page
{
public IKernel Kernel { get; private set; }
public PageBase() { Kernel = ...; }
public void Page_Init() { Kernel.Inject(this); }
}
This will allow you to property and method injection on any pages that
inherit from PageBase. Note that the constructor is incomplete --
you'll have to access the kernel in some static fashion. You should
be able to read it from the HttpApplication somehow.
(source: http://groups.google.com/group/ninject/browse_thread/thread/317fc48387399aa6, linked from Ninject with ASP.Net webforms and MVC):
This looks like it might work for me because it appears that I could apply this code to the existing, custom PageBase. But, I am hung up on the part in which the author says, "... the constructor is incomplete -- you'll have to access the kernel in some static fashion."
Does anyone have any idea what that sentence means, and how one might go about accessing the Ninject kernel in a static fashion?
You do not need to derive from a Ninject page base. You can alternatively use the NinjectHttpModule.
https://github.com/ninject/ninject.web/blob/master/src/Ninject.Web/NinjectHttpModule.cs