5

Is there anyway to access the current principal and before the request gets to the controller using Simple Injector? I am using OWIN and Asp.net identity.

I have a DbContext that I inject into my controllers, but this context will get it's connection string based off the authenticated user. This is what I have so far,

container.RegisterWebApiRequest<TenantDbContext>(); container.RegisterWebApiRequest<ITenantConnectionStringProvider>(() => new TenantConnectionStringProvider(container)); 

Then in my TenantConnectionStringProvider I have this,

var request = container.GetCurrentHttpRequestMessage(); var principal = request.GetRequestContext().Principal as ClaimsPrincipal; 

But the principal has no claims. I realized the claims are only available after the controller has been created. Does this mean it's just not possible because this step comes before the controller is created?

Edit: This is basically what the rest of the code does:

WebApi Controller

 public CampaignsController(TenantDbContext context, ILog log) { this.campaignService = campaignService; this.log = log; } 

Tenant context(just inherits from DbContext from EF):

 public TenantDbContext(ITenantConnectionStringProvider provider) : base(provider.GetConnectionString()) { } 

After messing around a bit, I was able to do this, but it feels very hacky.. I added an OWIN middleware that happens after authentication. I'm not sure why but I have all the authenticated users information here, but when it goes to the TenantConnectionStringProvider, none of this info is available on the HttpRequestMessage.

 app.Use(async (context, next) => { using (container.BeginExecutionContextScope()) { CallContext.LogicalSetData("Claims", context.Authentication.User.Claims); var request = (OwinRequest)context.Request; await next(); } }); 

Then in my TenantConnectionStringProvider I just did this,

 public string GetConnectionString() { var context = (IEnumerable<Claim>)CallContext.LogicalGetData("Claims"); return "test";//get claim from context to get the connection string } 

2 Answers 2

5

You can register a Func<ClaimsPrincipal> (factory) and inject it to your TenantConnectionStringProvider class :

public class TenantConnectionStringProvider : ITenantConnectionStringProvider { private readonly Func<ClaimsPrincipal> _claimsPrincipalFactory; public TenantConnectionStringProvider(Func<ClaimsPrincipal> claimsPrincipalFactory) { _claimsPrincipalFactory = claimsPrincipalFactory; } public void TestMethod() { // Access the current principal var principal = _claimsPrincipalFactory(); } } 

Registrations should look like that (not sure...):

// Register your types, for instance using the scoped lifestyle: container.RegisterSingleton<Func<ClaimsPrincipal>>(() => { // Not sure of which one to use. //return (ClaimsPrincipal)HttpContext.Current.User; //return (ClaimsPrincipal)Thread.CurrentPrincipal; return (ClaimsPrincipal)Context.User; }); container.RegisterWebApiRequest<ITenantConnectionStringProvider, TenantConnectionStringProvider>(); 
Sign up to request clarification or add additional context in comments.

9 Comments

I simplified your registration a bit by making the factory a singleton; since there's no need in creating a new delegate on each request. Note that you should never call the factory inside an injection constructor, as I explained in the comment on Erik's answer. In your case it even yields invalid results, because the principal might not be available during object graph construction. In other words, while a factory is meant to delay object construction, you don't delay anything, because the delegate is called inside the ctor.
Thanks @Steven. For the call of the factory in the constructor, it was just to give a example on how to get the principal. I will update my answer.
Upvoted. Note that the TenantConnectionStringProvider can become a singleton as well.
I prefer the Lazy class, otherwise each time the Func is used it's possible to get different results (generally speaking). For instance if someone decides to change the user, you get a different result. Same reason Microsoft made the mistake of making DateTime.Now a property and not a method, as methods are generally designed to return different results, while properties are generally static.
@ErikPhilips As a matter of fact: yes, Func is a bad idea, but usually not because it leaks, but because it complicates things for the consumer, while we shpuld strive to make things simpler for the consumer.
|
3

Does this mean it's just not possible because this step comes before the controller is created?

Definitely the way you've created it. I'm not completely familar with the but I bet using Lazy<> might be of benefit:

var request = container.GetCurrentHttpRequestMessage(); var principal = new Lazy<ClaimsPrincipal>(() => { return request.GetRequestContext().Principal as ClaimsPrincipal; }); 

Not tested, but when you actually need the principal value (i'm assume sometime later, in a different method in the same class) you can use principal.Value and it would then run and retrieve your ClaimsPrincipal. Granted these are huge assumptions because there is no code to see how everything is wired up. If you can provide how you get your connectionstring for the dbcontext (how that is all wired up) I might be able to give you a complete solution.

2 Comments

I don't think Lazy will help here, I need to access the claims immediately during injection. I will edit my post with what is going on.
@SSteveadoo you should not need the claim inside the injection constructor; this is bad practice as Mark Seemann explains here and since the principal is runtime data, this advice holds as well.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.