The EmployeeLinks class in the Repository layer.
using Contracts;
using Microsoft.AspNetCore.Routing;
using Entities.LinkModels;
using Entities.Models;
using Shared.DataTransferObjects;
using Microsoft.AspNetCore.Mvc.Formatters;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace Repository.Extensions.Utility
{
public class EmployeeLinks : IEmployeeLinks
{
private readonly LinkGenerator _linkGenerator;
private readonly IDataShaper<EmployeeDto> _dataShaper;
public EmployeeLinks(LinkGenerator linkGenerator, IDataShaper<EmployeeDto> dataShaper)
{
_linkGenerator = linkGenerator;
_dataShaper = dataShaper;
}
public LinkResponse TryGenerateLinks(IEnumerable<EmployeeDto> employeesDto, string fields, Guid companyId, HttpContext httpContext)
{
var shapedEmployees = ShapeData(employeesDto, fields);
if (ShouldGenerateLinks(httpContext))
return ReturnLinkdedEmployees(employeesDto, fields, companyId, httpContext, shapedEmployees);
return ReturnShapedEmployees(shapedEmployees);
}
private List<Entity> ShapeData(IEnumerable<EmployeeDto> employeesDto, string fields) =>
_dataShaper.ShapeData(employeesDto, fields)
.Select(e => e.Entity)
.ToList();
private bool ShouldGenerateLinks(HttpContext httpContext)
{
var mediaType = (MediaTypeHeaderValue)httpContext.Items["AcceptHeaderMediaType"];
return mediaType.SubTypeWithoutSuffix.EndsWith("hateoas", StringComparison.InvariantCultureIgnoreCase);
}
private LinkResponse ReturnShapedEmployees(List<Entity> shapedEmployees) =>
new LinkResponse { ShapedEntities = shapedEmployees };
private LinkResponse ReturnLinkdedEmployees(IEnumerable<EmployeeDto> employeeDto, string fields, Guid companyId,
HttpContext httpContext, List<Entity> shapedEmployees)
{
var employeeDtoList = employeeDto.ToList();
for(var index = 0; index < shapedEmployees.Count; index++)
{
var employeeLinks = CreateLinksForEmployee(httpContext, companyId, employeeDtoList[index].Id, fields);
shapedEmployees[index].Add("Links", employeeLinks);
}
var employeeCollection = new LinkCollectionWrapper<Entity>(shapedEmployees);
var linkedEmployees = CreateLinksForEmployees(httpContext, employeeCollection);
return new LinkResponse { HasLinks = true, LinkedEntities = linkedEmployees };
}
private List<Link> CreateLinksForEmployee(HttpContext httpContext, Guid companyId, Guid id, string fields = "")
{
var links = new List<Link>
{
new Link(_linkGenerator.GetUriByAction(httpContext, "GetEmployeeForCompany", "Employees", values: new {companyId, id, fields}),
"self",
"GET"),
new Link(_linkGenerator.GetUriByAction(httpContext,"DeleteEmployeeForCompany", "Employees", values: new { companyId, id }),
"delete_employee",
"DELETE"),
new Link(_linkGenerator.GetUriByAction(httpContext, "UpdateEmployeeForCompany", "Employees", values: new { companyId, id }),
"update_employee",
"PUT"),
new Link(_linkGenerator.GetUriByAction(httpContext, "PartiallyUpdateEmployeeForCompany", "Employees", values: new { companyId, id }),
"partially_update_employee",
"PATCH")
};
return links;
}
private LinkCollectionWrapper<Entity> CreateLinksForEmployees(HttpContext httpContext, LinkCollectionWrapper<Entity> employeesWrapper)
{
employeesWrapper.Links.Add(new Link(_linkGenerator.GetUriByAction(httpContext, "GetEmployeesForCompany", values: new { }),
"self",
"GET"));
return employeesWrapper;
}
}
}
When I try LinkGenerator class in Presentation layer i.e. Controller, ‘GetUriByAction’ works without any exception. But it doesn’t work in EmployeeLinks class in Repository layer. It shows the following error:
‘LinkGenerator’ does not contain a definition for ‘GetUriByAction’ and no accessible extension method ‘GetUriByAction’ accepting a first argument of type ‘LinkGenerator’ could be found (are you missing a using directive or an assembly reference?).
How can I fix it?
2
Answers
Link generator is part of the
Microsoft.AspNetCore.App.Ref
, but you won’t be able to install it in your Repository project.Instead modify your Repository
.csproj
file and add:This should resolve your issue.
According to the source of
GetUriByAction
, we can see thatHttpContext
is necessary for this method, whileHttpContext
is not able to be accessed directly in Repository layer. That’s the reason you got this error. In the meanwhile, this looks not to be a good idea to access Httpcontext in the Repository layer based on this design. I also found this question which had the same idea.If we want to do what you want to achieve, then we need to get HttpContext there,
IHttpContextAccessor
should be the answer. Related document. Let’s add the service in Program.csbuilder.Services.AddHttpContextAccessor();
, and then inject it into the Repository layer, then use_httpContextAccessor.HttpContext
as the method parameter.