marcusstarnes
marcusstarnes

Reputation: 6531

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.

Upvotes: 5

Views: 1233

Answers (1)

Steven
Steven

Reputation: 172606

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>.

Upvotes: 8

Related Questions