I still don’t have Dependency Injection down and I’m new with .Net Core (using 3.1.5). I’ve created an AuthorizationFilter for a WebAPI. What I’m still not understanding is how I can pass my Nlog to the attribute.
I have the following as my AuthorizaitonFilter
public class TokenAttribute : Attribute, IAuthorizationFilter
{
private readonly ILogger _logger;
public TokenAttribute(ILogger logger)
{
_logger = logger;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
_logger.LogInformation("Authorizing");
//Get the values from the Request Header
context.HttpContext.Request.Headers.TryGetValue("Api-Token", out var token);
context.HttpContext.Request.Headers.TryGetValue("Customer", out var customer);
//Query to look up Customer and Token
using (var ctx = new ModelContext())
{
var results = ctx.Token.FromSqlRaw(sbQuery.ToString()).ToList();
if (results == null || results.Count == 0)
{
context.Result = new BadRequestObjectResult("Invalid Token");
return;
}
return;
}
}
}
}
However, I’m getting an error on my Token attribute. If I leave it as just [Token]
I complains with a message: “There is no argument given that corresponds to the required formal parameter”
. I get that because the Token attribute’s constructor is looking for a ILogger.
[Token]
[AcceptVerbs(WebRequestMethods.Http.Get, WebRequestMethods.Http.Post)]
public ShiftRequest Post([FromBody] ShiftRequest m)
{
_logger.LogInformation("Calling POST command.");
Then if I try to pass _logger to the Token Attribute it complains with “An object reference is required for the non-static field ‘ShiftController._logger’”
.
[ApiController]
[Route("[controller]")]
public class ShiftController : ControllerBase
{
private IConfiguration _config;
private readonly ILogger<ShiftController> _logger;
public ShiftController(ILogger<ShiftController> logger, IConfiguration config)
{
_config = config;
_logger = logger;
}
[Token(_logger)]
[AcceptVerbs(WebRequestMethods.Http.Get, WebRequestMethods.Http.Post)]
public ShiftRequest Post([FromBody] ShiftRequest m)
{
_logger.LogInformation("Calling POST command.");
UPDATED CODE
public class TokenAuthorizationFilter : IAuthorizationFilter
{
private readonly ILogger<TokenAuthorizationFilter> _logger;
public TokenAuthorizationFilter(ILogger<TokenAuthorizationFilter> logger)
{
_logger = logger;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
_logger.LogInformation("Authorizing Token");
//Get the values from the Request Header
context.HttpContext.Request.Headers.TryGetValue("Api-Token", out var token);
context.HttpContext.Request.Headers.TryGetValue("Customer", out var customer);
//Query to check username and password
using (var ctx = new ModelContext())
{
var results = ctx.Token.FromSqlRaw(sbQuery.ToString()).ToList();
if (results == null || results.Count == 0)
{
context.Result = new BadRequestObjectResult("Invalid Token");
return;
}
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(context.ModelState);
}
return;
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<TokenAuthorizationFilter>();
services.AddControllersWithViews();
}
Controller
[ServiceFilter(typeof(TokenAuthorizationFilter))]
[AcceptVerbs(WebRequestMethods.Http.Get, WebRequestMethods.Http.Post)]
public ShiftRequest Post([FromBody] ShiftRequest m)
{
_logger.LogInformation("Calling POST command.");
You don't need to subclass Attribute
in this case. For authorization filters, these can be added via a [ServiceFilter(type)]
attribute on the action. When the ServiceFilter
attribute is used, all dependencies are injected automatically via ASP.NET Core's built-in service provider.
In your code, this would look something like [ServiceFilter(typeof(TokenAttribute))]
, although as a personal suggestion it might be more appropriate to name it something like TokenAuthorizationFilter
.
Note that you'll have to register your TokenAttribute
as a service inside Startup.cs
or wherever your HTTP pipeline setup is happening.