Search code examples
c#.netasp.net-mvcdependency-injectionsimple-injector

Configure Simple Injector to inject current authenticated user


I have a class which needs to set an IPrinciple object on construction, based on the current authenticated user.

I found some other code which I tried but it didn't work:

private readonly Lazy<IPrincipal> _principal;

public MyService(Lazy<IPrincipal> principal)
{
    _principal = principal;
}

And I configured Simple Injector like so:

container.Register(() => new Lazy<IPrincipal>(() => HttpContext.Current.User));

Apparently _principal is undefined/not set to an instance of an object when I try running this.

I also tried:

container.Register(() => new Lazy<IPrincipal>(() => Thread.CurrentPrincipal));

This allowed me to check _principal.Value.Identity.IsAuthenticated but was always returning false.


Solution

  • The root of your problems is caused by the fact that you inject runtime data into your components during object graph construction. As explained here, this is a bad idea.

    Instead, as the referenced article advices, you should delay the decision of requesting this runtime data until after the graph is built; at the time that this runtime data is available.

    You can do this by creating a custom IPrincipal implementation like this:

    public class HttpContextPrinciple : IPrincipal
    {
        public IIdentity Identity => HttpContext.Current.User.Identity;
        public bool IsInRole(string role) => HttpContext.Current.User.IsInRole(role);
    }
    

    And register it like this:

    container.RegisterSingleton<IPrincipal>(new HttpContextPrinciple());
    

    This allows you to inject IPrincipal directly into consumers like MyService. This simplifies the consumers, since they don't have to deal with leaky abstractions such as Lazy<T>.