I am working on an Asp.Net Core web application running on .NET Core 3.1.
For a wizard form, I am relying on a User class that holds the data stored in session. As we can access HttpContext from a controller, I had this GetUser() method inside my controller to retrieve session data when necessary :
private User GetUser()
{
var session = HttpContext.Session.GetComplexData<User>("user");
if (session == null)
{
User user = new User();
HttpContext.Session.SetComplexData("user", user);
}
return (User)HttpContext.Session.GetComplexData<User>("user");
}
Then I wanted to move that GetUser() method inside the User class so I used DI to provide that class's ctor with IHttpContextAccessor :
public class User
{
private readonly IHttpContextAccessor _contextAccessor;
public User(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
// fields removed here to keep it short
public User GetUser()
{
var session = _contextAccessor.HttpContext.Session.GetComplexData<User>("user");
if (session == null)
{
User user = new User(_contextAccessor);
_contextAccessor.HttpContext.Session.SetComplexData("user", user);
}
return (User)_contextAccessor.HttpContext.Session.GetComplexData<User>("user");
}
}
But then, in order to use that GetUser() method in my controller(s), I also have to provide this controller's ctor with IHttpContextAccessor as my User needs it to be instantiated :
public class NewController : Controller
{
private readonly IHttpContextAccessor _contextAccessor;
public NewController(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
[HttpGet]
public IActionResult Step1()
{
// Get session data
User user = new User(_contextAccessor); // <--
user = user.GetUser();
// Other code...
// ---
return View("Step1");
}
}
So my question is... Is it the right way to do it?
Or shall I just stick with my very first GetMethod() inside the controller without bothering with DI and duplicate it in other controllers if I need to access session there...?
Or perhaps you can show me something I don't know that would be more a good practice..
THanks
You don't want your User class to be tightly coupled to the HttpContext so your first method would be better. However, to improve readability and reusability (is that a word?) you could create users through an interface IUserManager and use dependency injection to provide the session there. The class would look something like this:
public class UserManager : IUserManager
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserManager(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public User Create()
{
// create user here using session in _httpContextAccessor
}
}
In order for this to work, don't forget to register the necessary dependencies in your container:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddTransient<IUserManager, UserManager>();
}
Source material: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-3.1#use-httpcontext-from-custom-components.
Related
I need to access ClaimsPrincipal within the service layer of a Net Core 6 app.
I could always just builder.Services.AddTransient<IHttpContextAccessor, HttpContextAccessor>(); in the Startup.cs & go my merry way but this is a no-no. Makes it difficult to test and more importantly this is a great example of leaky abstraction.
So, now what I have is the following
public class ClaimsProvider : IClaimsProvider
{
private readonly IHttpContextAccessor _httpContextAccessor;
public ClaimsProvider(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public ClaimsPrincipal? GetClaimsPrincipal()
{
return _httpContextAccessor.HttpContext?.User;
}
}
public interface IClaimsProvider
{
ClaimsPrincipal? GetClaimsPrincipal();
}
Within my Startup.cs AddScoped() that takes an IHttpContextAccessor and return an IClaimsProvider. Then I simply build all services against IClaimsProvider
builder.Services.AddScoped<IClaimsProvider>(provider =>
{
var httpContextAccessor = provider.GetRequiredService<IHttpContextAccessor>();
return new ClaimsProvider(httpContextAccessor);
});
And the usual route for my services where I inject it as a dependency
private readonly IClaimsProvider _claimsProvider;
public SomeService(
IWebHostEnvironment hostingEnvironment,
IMapper mapper, IClaimsProvider claimsProvider, ...)
{
_hostingEnvironment = hostingEnvironment ??
throw new ArgumentNullException(nameof(hostingEnvironment));
_mapper = mapper ??
throw new ArgumentNullException(nameof(mapper));
_claimsProvider = claimsProvider;
}
public void SomeMethod()
{
var u = _claimsProvider.GetClaimsPrincipal();
foreach (var claim in u.Claims)
{
Console.WriteLine($"{claim.Type} : {claim.Value}");
}
}
My question is that is the above approach ok? Potentially, is there any other approach that is better than the one shown above?
To prevent a leaky abstract (the need for an IHttpContextAsccessor in your service), I would recommend using the Adapter Pattern.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddHttpContextAccessor();
services.AddScoped<IClaimsProvider, HttpContextClaimsProvider>();
}
public IClaimsProvider
{
public ClaimsPrinciple ClaimsPrinciple { get; }
}
// Adapter
public HttpContextClaimsProvider : IClaimsProvider
{
public HttpContextClaimsProvider(IHttpContextAccessor httpContext)
{
ClaimsProvider = httpContext?.User?.Principle as ClaimsPrinciple;
}
public ClaimsPrinciple ClaimsPrinciple { get; private set; }
}
public class YourService : IYourService
{
private readonly IClaimsProvider _claimsProvider;
public YourService(IClaimsProvider claimsProvider)
{
_claimsProvider= claimsProvider;
}
}
In our design each controller action receives an FooRequest. This is a POCO object where the properties are filled from the model binder by using corresponding attributes:
public class FooRequest : RequestBase
{
[FromRoute]
public int Id { get; set; }
[FromQuery]
public DateTime? Start { get; set; }
[FromBody]
public SomeComplexObject Configuration { get; set; }
}
Additionally we made a derived class using the suffix WithUser that has a ClaimsPrincipal as additional property:
public class FooRequestWithUser : FooRequest, IRequest<FooResponse>
{
public ClaimsPrincipal User { get; set; }
}
In a next step we made a helper class that provides a helper method that can receive the request instance, a claims principal and a type T:
public class RequestBase
{
public T Of<T>(ClaimsPrincipal user) where T: class, new()
{
// Check if T has base of own type
// Create instance and iterate all props to get value
// from this and and set value in instance.
// Additionally use reflection to set user property.
}
}
When our normal request class is derived from this one, we can call it within our controller and create a model containing the user as an additional property and forward it into our services by using MediatR:
public IActionResult DoFoo(FooRequest request)
{
var requestWithUser = request.Of<FooRequestWithUser>(User);
var result = mediator.Send(requestWithUser);
return Ok(result);
}
By this approach the claims principal is bound to the request consumed by the service and not something it has to additionally receive. Also it makes clear, that this request must be somehow authenticated and the service should check for some potential permissions or similar.
The approach you have described is generally considered a valid way to access the ClaimsPrincipal in the service layer of a .NET Core 6 app, as it abstracts the implementation details of the IHttpContextAccessor, making it easier to test and maintain.
An alternative approach could be to use the built-in dependency injection in ASP.NET Core to directly inject the ClaimsPrincipal into the service, without the need for a separate IClaimsProvider interface.
You can do this by registering the ClaimsPrincipal as a service in the ConfigureServices method of the Startup class.
I am trying to build a user helper for core 2.2 to make it easier to get the current users information.
I keep getting back an object reference error on this current code
private static HtmlHelper _helper;
public UserHelper(HtmlHelper helper)
{
_helper = helper;
}
public static IIdentity GetUserId()
{
var userIdentity = _helper.ViewContext.HttpContext.User.Identity;
return userIdentity;
}
I've searched and most solutions work only in the controller or not at all. How can i go about getting this to work in a class?
What you're attempting to do here doesn't make sense. First, you cannot inject HtmlHelper and second, you cannot rely on an injected value from a static method. The static method is called on the class, not the instance, and the ivar you're attempt to use is only available on an instantiated class instance.
You'd probably be better served by an extension. For example, you can do something like:
public static class HtmlHelperExtensions
{
public static IIdentity GetUserId(this HtmlHelper helper)
{
var userIdentity = helper.ViewContext.HttpContext.User.Identity;
return userIdentity;
}
}
Then:
#Html.GetUserId()
Alternatively, you'd want to inject IHttpContextAccessor into your UserHelper, actually inject UserHelper to get an instance, and then have a non-static GetUserId method:
public class UserHelper
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserHelper(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public IIdentity GetUserId()
{
var userIdentity = _httpContextAccessor.HttpContext?.User.Identity;
return userIdentity;
}
}
Then, in your app's ConfigureServices:
services.AddHttpContextAccessor();
services.AddSingleton<UserHelper>();
In places like controller classes, you'd inject UserHelper just as anything else. In views, you can use:
#inject Namespace.To.UserHelper UserHelper
I've got an expensive "current user" obejct that I want to cache for the duration of the request. To do this I'm using the built-in DI in asp.net core, to create a ICurrentUser object when requested. It looks like this:
public class CurrentUserCache : ICurrentUser
{
public CurrentUserCache(IHttpContextAccessor httpContextAccessor, UserManager userManager)
{
var httpContextAccessor1 = httpContextAccessor;
_user = new Lazy<User>(() => httpContextAccessor1.HttpContext.User != null ? userManager.GetUserAsync(httpContextAccessor1.HttpContext.User).Result : null);
}
private Lazy<User> _user;
public User User {
get => _user.Value;
set {}
}
}
It's using a Lazy object to defer the retrieval of the object, since some controller actions might not need to make use of it.
My problem is - the code inside the lazy to get the user, is blocking (.Result). I don't want to do that, since it's quite expensive.
I don't know how to make this code async. I could possibly create a Lazy<Task<user>> to get the user, but then I can't await that in my user property, because it's a property and properties can't be async.
So - how can I turn this code into something that works well for async?
Thanks!
Turn the property into an awaitable function
public class CurrentUserCache : ICurrentUser {
public CurrentUserCache(IHttpContextAccessor httpContextAccessor, UserManager userManager) {
_user = new Lazy<Task<User>>(() =>
userManager.GetUserAsync(httpContextAccessor.HttpContext.User)
);
}
private Lazy<Task<User>> _user;
public Task<User> GetUserAsync() {
return _user.Value;
}
}
I am trying to create a UserService that I can inject in my classes, that will hold the user currently logged in to my system.
I am using CastleWindsor as my container.
Now my problem is that I am trying to make my UserService disposable, so that the databaseconnection fetching the user on creating will also be disposed when the object is destroyed.
I added the following setup in my Global.asax.cs:
private static void BootstrapContainer()
{
_container = new WindsorContainer().Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
GlobalConfiguration.Configuration.DependencyResolver = new WindsorDependencyResolver(_container.Kernel);
_container.Register(Component.For<IUserService>()
.LifestylePerWebRequest()
.ImplementedBy<UserService>());
_container.Register(Component.For<IPrincipal>()
.LifeStyle.PerWebRequest
.UsingFactoryMethod(() => HttpContext.Current.User));
}
Which is called in my Application_Start.
My UserService code is as follows:
public interface IUserService
{
OrganisationBruger User { get; }
int UserId { get; }
}
public class UserService : IUserService, IDisposable
{
private readonly IPrincipal _principal;
private OrganisationBruger _user;
private readonly DatabaseDataContext _db;
public UserService(IPrincipal principal, IDatabaseDataContextFactory dataContextFactory)
{
_principal = principal;
_db = dataContextFactory.GetDataContext();
}
public OrganisationBruger User => _user ?? (_user = GetUser());
public int UserId => Convert.ToInt32(_principal.Identity.Name);
private OrganisationBruger GetUser()
{
return _db.OrganisationBrugers.Single(u => u.ID == UserId);
}
public void Dispose()
{
_db.Dispose();
}
}
When I Debug my code I can see on the very first request I fire it correctly creates the class UserService.cs and then disposes it after the webrequest. Now my problem is the second web request does not seem to call the constructor anymore thus just reusing the formerly created object. This leads to the DatabaseContext already being disposed of.
I thought that LifestylePerWebRequest meant that the UserService would get recreated on every request. Can anyone help me understand this?
So first of all I had overlook the "registration of the module"-part in the documentation. You need to add the following to your web.config:
<httpModules>
<add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor"/>
</httpModules>
Second of all I was not a hundred percent sure how the dependency resolver worked. The problem was that one of the modules using my UserService as a dependency had its lifecycle set to Singleton which is default behavior when you specify nothing about the lifecycle when registering your module with the container.
I fixed the problem by making sure that every module that is using my UserService as dependency is also registered with a lifecycle of LifestylePerWebRequest() or LifestyleTransient().
You should double check if you have any other interface which use IUserService overwrites the lifestyle.
In that case, Castle windsor will not resolve IUserService for each request because ITest is set to singleton.
For example
_container.Register(Component.For<ITest>()
.LifestyleSingleton()
.ImplementedBy<Test>());
public interface ITest
{
}
public class Test: ITest
{
private readonly IUserService _ser;
public Test(IUserService ser)
{
_ser= ser;
}
}
I have a WindsorHttpControllerActivator that implements IHttpControllerActivator. It registers the controller for disposal which ensures a new controller gets created on each request by destroying the old one. This occurs when .LifestylePerWebRequest() completes each request.
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
var controller =
(IHttpController)_container.Resolve(controllerType);
// Controller disposal ensures new controller for each request, hence DbContexts are fresh and pull fresh data from the DB.
request.RegisterForDispose(
new Release(
() => _container.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action _release;
public Release(Action release)
{
_release = release;
}
public void Dispose()
{
_release();
}
}
I have the following class and interface structure and I'm having a hard time trying to get the code to do what I need.
public interface IUserManager
{
int Add(User user);
}
public class UserManagerA : IUserManager{}
public class UserManagerB : IUserManager{}
In this example I'm using Ninject as the IoC container but I'm open to changing it if some other container resolves the issue:
This is inside my NinjectWebCommon.cs:
void RegisterServices(IKernel kernel)
{
string userRole = CurrentUser.Role;//this gets the user logged in
//This is the part I do not how to do
//I wish I could just type this in:
kernel.Bind<IUserManager>().To<UserManagerA>()
.When(userRole == "RoleA"); // this doesn't work obviously
kernel.Bind<IUserManager>().To<UserManagerB>()
.When(userRole == "RoleB"); // same doesn't work
}
All of that so that in my (MVC) controller I can do this:
public class UserController
{
private readonly IUserManager _userManager;
public UserController(IUserManager userManager)
{
_userManager = userManager;
}
public ActionResult Add(User user)
{
//this would call the correct manager
//based on the userRole
_userManager.Add(user);
}
}
I've been reading articles about Abstract Factory but haven't found one that explains how to integrate the factory with the IoC container and pass a parameter obtained at run-time to resolve the implementations.
Create a class responsible for providing the correct UserManager and inject this to your controller:
public class UserManagerProvider : IUserManagerProvider
{
private readonly IContext _context;
public UserManagerProvider(IContext context)
{
_context = context;
}
public IUserManager Create(User currentUser)
{
if (currentUser.Role == "User A")
return _context.Kernel.Get<UserManagerA>();
if (currentUser.Role == "User B")
return _context.Kernel.Get<UserManagerB>();
// Or bind and resolve by name
// _context.Kernel.Get<IUserManager>(currentUser.Role);
}
}
And in controller:
private readonly IUserManager _userManager;
public UserController(IUserManagerProvider userManagerProvider)
{
_userManager = userManagerProvider.Create(CurrentUser);
}
Also, as a side note you should probably have a CurrentUserProvider responsible for getting the current user. Relying on a static method will make things difficult to unit test and you're essentially hiding a dependency in all classes that reference it:
private readonly IUserManager _userManager;
private readonly User _currentUser;
public UserController(IUserManagerProvider userManagerProvider, ICurrentUserProvider currentUserProvider)
{
_currentUser = currentUserProvider.GetUser();
_userManager = userManagerProvider.Create(_currentUser);
}
Provided the number of IUserManager implementations is not very many (not likely to reach 100 implementations), you can use a Strategy Pattern to resolve all of your UserManager instances during composition and then pick the best instance for use at runtime.
First, we need a way to map IUserManager implementations to roles.
public interface IUserManager
{
int Add(User user);
bool AppliesTo(string userRole);
}
public class UserManagerA : IUserManager
{
// Add method omitted
public bool AppliesTo(string userRole)
{
// Note that it is entirely possible to
// make this work with multiple roles and/or
// multiple conditions.
return (userRole == "RoleA");
}
}
public class UserManagerB : IUserManager
{
// Add method omitted
public bool AppliesTo(string userRole)
{
return (userRole == "RoleB");
}
}
Then we need a strategy class that simply picks the correct instance based on the userRole. The IUserManager instances are supplied by the DI container when the application is composed.
public interface IUserManagerStrategy
{
IUserManager GetManager(string userRole);
}
public class UserManagerStrategy
: IUserManagerStrategy
{
private readonly IUserManager[] userManagers;
public UserManagerStrategy(IUserManager[] userManagers)
{
if (userManagers == null)
throw new ArgumentNullException("userManagers");
this.userManagers = userManagers;
}
public IUserManager GetManager(string userRole)
{
var manager = this.userManagers.FirstOrDefault(x => x.AppliesTo(userRole));
if (manager == null && !string.IsNullOrEmpty(userRole))
{
// Note that you could optionally specify a default value
// here instead of throwing an exception.
throw new Exception(string.Format("User Manager for {0} not found", userRole));
}
return manager;
}
}
Usage
public class SomeService : ISomeService
{
private readonly IUserManagerStrategy userManagerStrategy;
public SomeService(IUserManagerStrategy userManagerStrategy)
{
if (userManagerStrategy == null)
throw new ArgumentNullException("userManagerStrategy");
this.userManagerStrategy = userManagerStrategy;
}
public void DoSomething()
{
string userRole = CurrentUser.Role;//this gets the user logged in
// Get the correct UserManger according to the role
IUserManager userManager = this.userManagerStrategy.GetManger(userRole);
// Do something with userManger
}
}
void RegisterServices(IKernel kernel)
{
kernel.Bind<IUserManager>().To<UserManagerA>();
kernel.Bind<IUserManager>().To<UserManagerB>();
// Ninject will automatically supply both IUserManager instances here
kernel.Bind<IUserManagerStrategy>().To<UserManagerStrategy>();
kernel.Bind<ISomeService>().To<SomeService>();
}
This method doesn't require you to inject the container into the application. There is no service location being used.
Note also that there is no switch case statement that would have to be modified every time you add a new UserManager to the application. The logic of when to use a UserManager is part of the UserManager implementation and the order in which the logic is executed is determined by the DI configuration.
In addition, this will work regardless of which DI container you are using.
You could combine this with the CurrentUserProvider from RagtimeWilly's answer for a clean way to get the user role into the service where this is used.
Reference: Best way to use StructureMap to implement Strategy pattern