You could use a filter, specifically, an action filter, which could:
- Run code immediately before and after an action method is called.
- Can change the arguments passed into an action.
- Can change the result returned from the action.
- Are not supported in Razor Pages.
An example is
public class MySampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
}
}
Here you could prepare a scoped service, load the user based on the service and then reuse it in any service that requires that data.
Even without the filter, you could simply create a UserService with a scoped lifetime, load the user there and use it anywhere in your services.
In our system we are doing something similar:
A service to load the session data:
public class ClientTokenService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public ClientTokenService(
IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public Profile LoadProfile()
{
if (_httpContextAccessor.HttpContext.User == null)
{
throw new Exception("No user claims found to load Profile");
}
var user = _httpContextAccessor.HttpContext.User;
var numberType = (NumberType)int.Parse(user.FindFirst("numberType").Value);
var profileType = (PackagePlan)int.Parse(user.FindFirst("profileType").Value);
var lineOfBusiness = (LineOfBusiness)int.Parse(user.FindFirst("lineOfBusiness").Value);
// More stuff
// Prepare the profile data
return new Profile(
user.FindFirst("number").Value,
user.FindFirst("contractId").Value,
numberType,
profileType,
user.FindFirst("cc")?.Value,
user.FindFirst("app").Value,
user.FindFirst("clickId")?.Value,
user.FindFirst("wifi") != null,
lineOfBusiness
);
}
}
This service can be transient, and then a scoped service which saves the data
public class ClientSessionContext
{
public Profile Profile { get; }
public ClientSessionContext(
ClientTokenService sessionService)
{
Profile = sessionService.LoadProfile();
}
}
Declare this service as scoped, so this class is initialized just once per request
Statup.cs
services.AddScoped<ClientSessionContext>();
Then just inject this service anywhere where you need access to the user data.