I just ran across the need for this as well. I've stored some configuration data in GlobalContext via the main application thread, but I'm also running a data access query on a background thread - which needs access to the configuration data as well.
One solution that I think will work - modify ApplicationContext to use the AppDomain GetData / SetData methods (just on the client-side obviously). Remote data portal will still need to use thread-local storage.
I'm working on a prototype now to see if it will work. However, it'd be very nice if this (or something similar) were incorporated into the common CSLA code base (hint, hint).
Didn't take long at all to get working. I'm attaching a modified copy of ApplicationContext (C# version) that uses AppDomain storage on the client and thread-local storage on the "server". Just had to modify a couple of lines of code. In my *very limited* testing, everything is working as expected.
Forgot to mention this - my quick workup is not thread-safe. You'd need to code that in as well. I didn't bother, since I mainly wanted to see if it worked first. :-)
Here's hoping Rocky can incorporate a multi-threaded ApplicationContext object in CSLA.
This is a good thought. I don't know about making the whole object threadsafe though. Making it threadsafe would have a negative performance impact, even if you aren't using threads. Most people don't, and so they'd pay this cost for nothing.
I'd rather opt for the solution Microsoft uses pretty globally, which is to not be threadsafe, but rather provide a syncroot object you can use to implement your own locking.
Though that may not be realistic either, given that you might be making data portal calls on multiple threads. Of course (as I think about this), that is highly problematic, because the data portal just replaces the client data with the server data - so if you actually use/alter global context data on the server you'd lose some of that data in the case that multiple data portal calls occur at once.
Given that issue, it is clear that this requires quite a lot of thought - because the data portal might have to try and do some intelligent merge of data in globalcontext - and sitting here right now it isn't clear to me how such a thing would work - because that data is free-form, and so there's no guaranteed way for the data portal to match items to other items when doing a merge...
So it might be the case that globalcontext must be per-thread, while the User and ClientContext values can actually be client-wide.
I see the dilemna with the GlobalContext object - if you were running locally, there wouldn't be an issue, but if you were using remoting, there is the chance for data to be overwritten.
I don't see any difficulty with the ClientContext object, though, since it's not restored after a DataPortal call. Store ClientContext in the app domain and all we need is a thread-safe way of getting/setting ClientContext and we should be good (I think).
Right, I agree. I think that storing the ClientContext in the AppDomain should be fine, and leaving GlobalContext on the thread should avoid the merge issue.
The ClientContext is already a collection, and so has a SyncRoot property you can use for threadsafe access to its contents. I don't think I need to do anything there.
The ClientContext property itself is a different matter, and it needs to become threadsafe - meaning ClientContext, GetClientContext() and SetClientContext() all need to include locking code. I have put this into the code in cvs, and it passes the (updated) nunit tests. Whether I created any possible race conditions remains to be seen, but I don't think I did cause any such problems.
Copyright (c) Marimer LLC