I'm trying to create an ActionFilter
that will read the Accept-Language
header and find if it matches any value in locale
and if it does not match, use the a default value which is "en"
.
First of all, this is my handler:
using MediatR;
using Microsoft.EntityFrameworkCore;
using Subscription.Domain.Common;
using Subscription.Domain.Exceptions;
using Subscription.Infrastructure.Configuration;
using System.Net;
namespace Subscription.API.Application.Package.Queries.Get
{
public class GetHandler : IRequestHandler<GetRequest, EntityResponseModel>
{
private readonly SubscriptionContext _context;
private readonly IHttpContextAccessor _httpContext;
public GetHandler(SubscriptionContext context, IHttpContextAccessor httpContext)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
_httpContext = httpContext;
}
public async Task<EntityResponseModel> Handle(GetRequest request, CancellationToken cancellationToken)
{
var lang = _httpContext.HttpContext.Request.Headers["Accept-Language"].ToString();
var packages = await _context.Packages.Where(x => !x.IsDeleted)
.Select(x => new GetResponseModel()
{
Id = x.Id,
BrandId = x.BrandId,
StartAt = x.StartAt,
IconUrl = x.IconUrl,
ImageUrl = x.ImageUrl,
CreatedAt = x.CreatedDate,
Title = x.PackageTranslations.FirstOrDefault(pt => pt.PackageId == x.Id && pt.Locale.Equals(lang)).Title,
Description = x.PackageTranslations.FirstOrDefault(pt => pt.PackageId == x.Id && pt.Locale.Equals(lang)).Description
}).ToListAsync();
if (!packages.Any())
{
throw new DomainException(HttpStatusCode.NotFound, "No record found.");
}
return new EntityResponseModel()
{
Data = packages
};
}
}
}
And this is the controller:
using Microsoft.AspNetCore.Mvc;
using MediatR;
using Subscription.API.Application.Package.Queries.Get;
using Subscription.API.Application.Bundle.Queries.GetById;
using Subscription.API.Filters;
namespace Subscription.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PackagesController : ControllerBase
{
private readonly IMediator _mediator;
public PackagesController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet]
[ValidateHeaders]
public async Task<ActionResult> GetAll()
{
var response = await _mediator.Send(new GetRequest() { });
return Ok(response);
}
}
}
This the filter class:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Subscription.API.Filters
{
public class ValidateHeaders : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var headers = context.HttpContext.Request.Headers;
// need to do something here
}
}
}
So, basically what I need is to create a filter that:
- Check the
Accept-Language
header if it have a value that matches locale - If it does not have a value that matches it, return string with the default value which is
"en"
Any idea what I should do?
CodePudding user response:
You can do this in 2 different ways;
- Action Filter
- Middleware
1.Action Filter
If you use this action filter, you have to write this attribute on each endpoint.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Subscription.API.Filters
{
public class ValidateHeaders : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var languageHeader = context.HttpContext.Request.Headers.AcceptLanguage;
if (string.IsNullOrWhiteSpace(languageHeader))
context.HttpContext.Request.Headers.AcceptLanguage = "en";
}
}
}
2.Middleware
If you write it as middleware, it will be enough to place this middleware in the first place in the request pipeline.
public class ValidateHeadersMiddleware
{
private readonly RequestDelegate _next;
public ValidateHeadersMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var languageHeader = context.Request.Headers.AcceptLanguage;
if (string.IsNullOrWhiteSpace(languageHeader))
context.Request.Headers.AcceptLanguage = "en";
//Continue processing
if (_next != null)
await _next.Invoke(context);
}
}
This will effect all requests.
public static class MiddlewareExtension
{
public static IApplicationBuilder UseHeaderValidation(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ValidateHeadersMiddleware>();
}
}
In the Configure
method in Startup.cs
or minimal api configuration in Program.cs
, use this middleware;
...
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHeaderValidation();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
...