Lightweight Composition Provider with UserIdentity scope

May 22, 2012 at 1:39 PM

Hello,

I have a part with I want to be shared per user. So I added the [Shared(Boundaries.UserIdentity)] attribute to my part.

But still the part is created every time. If I just apply the [Shared] attrbute, it works as expected, the part is created just once.

For testing this I use a GenericPrincipal:

 
protected void Application_AuthenticateRequest()
{
   HttpContext.Current.User = new GenericPrincipal(new GenericIdentity("TestUser"), null );
}

Any idea what I am doing wrong?

Regards, Jaap

May 23, 2012 at 7:04 PM

Hi there!

Boundaries.UserIdentity isn't precisely what you've interpreted it to be here. The composition provider maps UserIdentity to the current web request; it doesn't maintain one instance per identity.

The purpose of this boundary is to enable code to be shared between web and back-end processes. In a back-end process it is quite common to have a single user identity across multiple units of work, while in a web site, user identity maps to the current unit of work (the request). Fine-grained control of sharing boundaries (data, user and web request) means that different host apps can share components more flexibly.

Hope this helps clarify things, I know it is a very light description - we're intending to write more on this topic in the near future. If you have more questions please send them through :)

Regards,
Nick

May 23, 2012 at 7:17 PM

Ok, think that is clear. But let me then discribe my case.

I have a part of which I would typically save an instance on the ASP.NET Session state, so per client session.

How should I do that with the MVC Lightweight container?

Regards, Jaap

May 23, 2012 at 7:28 PM

Great, thanks for following up.

I don't think there's a single way to approach this - it is possible (e.g. by modifying the composition provider code) to do what you want via composition.

In practice I've tried this once and didn't have a great experience with it. I found it fragile because:

  • You need to be careful when extending/refactoring the app that everything needed by session-scoped components is serializable
  • The initialization logic for new session state often depends on per-request information/parts that may not be themselves initialized at the right time

The most effective solution I've used is to write parts that encapsulate interactions with the Session objects, so that session state is treated like data by the app. For example if you need to store something like the user's ten recent transactions in session state, then creating a UserHistory part with a RecentTransactions property is the kind of solution I'd go for. The RecentTransactions property would go to the Session for data, and be set up as a per-request part so that it could get information about the user and consume other parts at the request level. (Sprinkle with interfaces/abstractions as needed, naturally.)

Your scenario may be different of course, and others may have better suggestions, but this has been the best solution for me personally.

Regards,
Nick

May 24, 2012 at 6:40 AM

Ok, thank you. This is a good way to go, I think.

Just good to know that I didn't mis something that MEF supports out of the box.

Thanks, Jaap