MEF, LoadCatalog and Invalid cross-thread access

Feb 14, 2011 at 10:58 PM
Edited Feb 14, 2011 at 11:04 PM

Hi,

I've got a "Show" IResult that I've been beaten into submission with over the past two afternoon.

It (portions of it, at least) are based on the ShowScreen and LoadCatalog examples given in the docs on IResult and Coroutines, but modified with a set of static methods such that I can specify either a type to inject and a target IConductor, or a contract name and target IConductor.

I put in there some trivial code so that, if you ask for a screen with, for example "ExternalApp;MyViewModel" the routine will first download 'ExternalApp.xap",create a DeploymentCatalog for it, and then yank out the ViewModel exported as "MyViewModel". This is all done around a fluent-ish interface, e.g:

yield return Show
              .ScreenOfType<SecondViewModel>()
              .PassingValues(data)
              .InContainer<IShell>();

or

yield return Show
                .ScreenNamed("ExternalApp;MyViewModel")
                .PassingValues(data)
                .InContainer<IShell>();

All well and good for the project that I was working on (a small test app to figure out what I was building) and another this morning where I plugged it into a colleagues code to demo how it worked. Which was 'like a charm' for all of the test scenarios I threw at it.

So, I came to plumbing this into our full prototype application and I immediately started getting an exception thrown when the DeploymentCatalog async download completes:

{System.InvalidOperationException: The package downloaded successfully but an error occurred while reading the contents of the package. See the inner exception for more details. ---> System.UnauthorizedAccessException: Invalid cross-thread access.
   at MS.Internal.XcpImports.CheckThread()
  ..... etc.

I've tried this with a copy of the LoadCatalog class ripped straight from the documention and get the same exception, along with a couple of dozen other ways of trying to get around this and can't seem to resolve it.

I know this isn't strictly speaking a Caliburn.Micro issue (btw, wicked framework), but I wondered if anyone had tried something similar or come across the same problem.

Happy to post an example somewhere, but - as I say - the routine works fine everywhere else than our full-blown prototype application (same machine, run under the same account, both with IIS vdir's instead of under Cassini).

I can't see anything different in how I'm calling the routine (other than, in the test apps this is the first yield in an IEnumerable event wired to a button, and in the one that fails it's the second).

Any ideas would really be appreciated at this point.

Thanks

Paul

Coordinator
Feb 15, 2011 at 1:49 PM

"and in the one that fails it's the second"

Try raising the completed event for the first IResult specifically on the UI thread by using Execute.OnUIThread(() => Completed(this, new ResultCompletionEventArgs());

My guess is that the first IResult is completing on the background thread. So the second IResult starts on the background thread, but is required to start on the UI thread.

Feb 15, 2011 at 6:06 PM

Genius! Thanks, Rob, that worked a treat.