Search code examples
asp.net-core.net-corecustom-attributeshttpcontextfilterattribute

Inject httpcontext into custom attribute outside controller in .net core


I need to inject httpcontext into custom attribute that is used outside the controller. I found several solutions how to do it in controller, but my case is little tricky. Now I have following code in my PermissionController

[PermissionFilter(PermissionEnum.Permission, AccessLevelEnum.Create)] <-- it works perfectly
[HttpPost("users/{userId}")]
public async Task<IActionResult> 
  AssignPermissionToUser([FromBody] List<PermissionToVM> permissions, int userId)
{
    await _permissionService.Assign(permissions); <-- .Assign() extension
    //code goes here
}

In the method above there is a call of extension method .Assign. This method code is available below.

//[SecondPermissionFilter(PermissionEnum.Permission,
   AccessLevelEnum.Create)] <-- here I check permissions but don't 
   know how to inject the httpcontext
public async Task Assign(List<PermissionToVM> permissions)
{
    //code goes here
}

As mentioned in many websites I visited f.e. here https://dotnetcoretutorials.com/2017/01/05/accessing-httpcontext-asp-net-core/ injecting of httpcontext outside the controller can be done using IHttpContextAccessor. The problem is that I don't know how to use it without passing it into constructor. My custom attribute should be called as decorator [SecondPermissionFilter(PermissionEnum.Permission, AccessLevelEnum.Create)] when only permission settings should be passed, so there is no any reference to httpcontextaccessor.

Is this even possible? If not, there is maybe another way to do this?

EDIT: Here is the code of SecondPermissionFilter class:

public sealed class SecondPermissionFilterAttribute : Attribute
{
    private readonly PermissionEnum _requestedPermission;
    private readonly IEnumerable<AccessLevelEnum> _accessLevelCollection;
    private readonly IHttpContextAccessor _contextAccessor; //<-- how to inject?

    public PermissionFilterAttribute(PermissionEnum requestedPermission, params AccessLevelEnum[] accessLevelCollection)
    {
        _requestedPermission = requestedPermission;
        _accessLevelCollection = accessLevelCollection;
    }
}

Solution

  • What you are after is something called Property Injection. As per the official docs this is not something that is supported out of the box by the .NET Core DI Container.

    You can however use a third party library such as Ninject or Autofac - both of which are available via NuGet.

    In my opinion the Ninject syntax is nicer, however as noted in this answer, and this answer property injection itself is considered bad practice. So if possible I would try to avoid it.

    So you should instead use one of the three methods specified by the filter documentation, this answer breaks things down a bit more.

    Edit

    This answer deals specificically with Attribute injection, the second answer looks to achieve this without external dependencies.