I'm working on an API and implementing the Onion Architecture, which means my controller is in another project. I'm trying to configure my API to return HATEOAS links for both JSON and XML.
I did a check for the Accept
request header to determine this, but when I passed my HttpContext
in my controller action body, I get this error:
System.NullReferenceException: Object reference not set to an instance of an object.
mediaType was null.
Here's my ValidateMediaTypeAttribute
class:
public class ValidateMediaTypeAttribute : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
var acceptHeaderPresent = context.HttpContext.Request.Headers.ContainsKey("Accept");
if (!acceptHeaderPresent)
{
context.Result = new BadRequestObjectResult($"Accept header is missing.");
return;
}
var mediaType = context.HttpContext.Request.Headers["Accept"].FirstOrDefault();
if (!MediaTypeHeaderValue.TryParse(mediaType, out MediaTypeHeaderValue? outMediaType))
{
context.Result = new BadRequestObjectResult($"Media type not present. Please add Accept header with the required media type.");
return;
}
context.HttpContext.Items.Add("AcceptHeaderMediaType", outMediaType);
}
public void OnActionExecuting(ActionExecutingContext context)
{
}
}
And here's my controller
public async Task<IActionResult> GetEmployeesForCompany(Guid companyId, [FromQuery] EmployeeParameters employeeParameters)
{
var linkParams = new LinkParameters(employeeParameters, _httpContextAccessor.HttpContext);
var pagedResult = await _service.EmployeeService.GetEmployeesAsync(companyId, linkParams, trackChanges: false);
Response.Headers.Add("X-Pagination", JsonSerializer.Serialize(pagedResult.metaData));
return pagedResult.linkResponse.HasLinks ? Ok(pagedResult.linkResponse.LinkedEntities) : Ok(pagedResult.linkResponse.ShapedEntities);
}
This is my TryGenerateLinks
method:
public LinkResponse TryGenerateLinks(IEnumerable<EmployeeDto> employeesDto, string fields, Guid companyId, HttpContext httpContext)
{
var shapedEmployees = ShapeData(employeesDto, fields);
if (ShouldGenerateLinks(httpContext))
return ReturnLinkedEmployees(employeesDto, fields, companyId, httpContext, shapedEmployees);
return ReturnShapedEmployees(shapedEmployees);
}
private List<Entity> ShapeData(IEnumerable<EmployeeDto> employeesDto, string fields) =>
_dataShaper.ShapedData(employeesDto, fields).Select(e => e.Entity).ToList();
private bool ShouldGenerateLinks(HttpContext httpContext)
{
var mediaType = (MediaTypeHeaderValue)httpContext.Items["AcceptHeaderMediaType"]; // Error occurs here
return mediaType.SubTypeWithoutSuffix.EndsWith("hateoas", StringComparison.InvariantCultureIgnoreCase)
}