none
MEF: DeploymentCatalog.DownloadCompleted being called repeatedly

    Question

  • Just getting started with MEF and trying a basic scenario with DeploymentCatalog.

     

    I have not set up any other MEF components anywhere else in my main application.

     

    Based on an id key, I download a particular xap:

     

                    DeploymentCatalog dc = new DeploymentCatalog(uri);

                    dc.DownloadCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(dc_DownloadCompleted);               

                    dc.DownloadAsync();

     

    In the completed handler, I’m trying this:

            void dc_DownloadCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
            {
                DeploymentCatalog catalog = e.UserState as DeploymentCatalog;
    
                var container = new CompositionContainer(catalog);
    
                UserControl w = container.GetExportedValue<IWidget>() as UserControl;
    
                ...
    
            }
    
    


     

    And it works – I can add the user control ‘w’ to my hosting control and do stuff with it.

     

    The problem is that, if I make the same call again to download another instance (the user can have 0-n instances), DownloadCompleted gets called for the new instance and every previous instance as well.  I tried unregistering/unattaching the event handler during the DownloadCompleted handler but that doesn’t seem to make any difference.

     

    What’s going on?

     

    Thanks!

    Friday, April 29, 2011 2:43 PM

Answers

  • Well, I'm embarrassed to say what the problem turned out to be..

    I have a method that gets called before all this.  In that method I call a websevice to get the address of the widget xap I need to download.  The problem was that I was always adding a new OnCompleted event handler to THAT webservice call, which caused everything to stack up, of course.

    Bah, sorry for the noise, but thanks again for your time + responses Jeremy.

    Friday, April 29, 2011 7:30 PM

All replies

  • There are two problems. First, you should really focus on having a single composition container, and not create it each time. The container can hold an AggregateCatalog that then hosts the multiple deployment ctalogs.

    Second, unhook the handler in your event. At the start of the event do this:

    ((DeploymentCatalog)sender).DownloadCompleted -= dc_DownloadCompleted;

     

    Friday, April 29, 2011 3:21 PM
  • Hi Jeremy, thanks so much for your response. 

    Unfortunately though, if you take a look at my original post, I mentioned that I've 'tried unregistering the event handler during the DownloadCompleted handler but that doesn't seem to make any difference'.  I tried the exact code you posted before I made my post, but it didn't help.

    I know I can make things more robust later, but for now I'm just trying to get this simple scenario working, and understand why it's currently not.  :)

     

    Friday, April 29, 2011 4:39 PM
  • I missed that, sorry, but you also missed the other part of my answer. You shouldn't be making a new container each time. It should be one container with one aggregate catalog and a collection of deployment catalogs.

    Friday, April 29, 2011 4:56 PM
  • Ah sorry, I didn't realize that was your intention.  I thought you were just suggesting as an aside that one container is the preferred practice.

    I'll give that a shot.  While I'm doing so, could you offer an explanation of why a single container is necessary, and why the previous instances would still be triggering DownloadCompleted?  I'm trying to understand the bigger picture from a conceptual point of view.  It'd be muchly appreciated. :)

    Friday, April 29, 2011 5:11 PM
  • Have you read any blogs/tutorials/quick starts for MEF? Or are you jumping in?

    It's a little tough to explain everything conceptually here. It's fresh in my head as I'm working on a video series now but in a nutshell, it's like any Inversion of Control container you might use (though it's not precisely that, it's a good analogy) - Unity, Ninject, StructureMap, all of those are going to provide a default "global" container. You can have nested containers but that really defeats the purpose of the application-wide concerns. There should be at least a master container for the application as a whole, otherwise everything will be handled in "silos". A well-designed MEF application typically only composes parts once. That's because the dependencies are hierarchical, and therefore are wired up in a tree, and recomposition means as new parts are introduced, they are automatically composed and then events like IPartImportsSatisfiedNotification can fire to react.

    I don't know why the multiple containers would be having that behavior because I've never tried to use more than one container. I've been doing MEF since the early preview on large and small applications and everything in between so I'm just trying to get the variables down to the controlled scenario to make it easier to troubleshoot.

    If you care to take a look, this is the post that deals specifically with container/XAP management:

    http://csharperimage.jeremylikness.com/2011/01/jounce-part-9-static-and-dynamic-module.html

    Friday, April 29, 2011 5:37 PM
  • Thanks Jeremy.   Yep, I've been reading a ton of blogs/posts/documentation over the last few days.  It seems like the more I read, the less concrete my conceptual understanding is!  Lots of folks blog stuff like 'copy this code, delete everything in the file and paste this, and it works, see!?' :)  Or 'I've gone ahead and implemented this factory that does all this magic for you..'  That's cool and all, but doesn't really help us understand it at a fundamental/conceptual level.

    Regarding 'composing once' - What about a Dashboard/Widget scenario where users can choose widgets from an online directory and load them on demand to add to their Dashboards?  That's the scenario I'm working towards, so when you say composing once, I'm thinking that pattern won't work for me.  Know what I mean?

    I do really appreciate your responses.  I HAVE read a lot, but between the official SL API docs and codeplex with stale docs and everyone's blogs from 18+ months ago..  it's challenging. :)

    Friday, April 29, 2011 5:54 PM
  • I should have said "explicitly composing." Once you've run compose parts, that's it - you're done.

    That's because when you dynamically load a plug-in, it triggers recomposition. There is no need for you to do anything but add the deployment catalog to the main aggregate catalog already sitting in the master container. Nothing else. All dependencies that are relevant will be notified and updated provided they are tagged with "AllowRecomposition=true." We do dynamic modules and plug-ins all of the time and it works perfectly with MEF.

    I'm trying to help close the gaps with the video series I'm recording now, Fundamentals of the Managed Extensibility Framework. It will cover everything with live screen casts, code examples, etc. I'll keep everyone posted via my blog when it is available.

    Friday, April 29, 2011 6:07 PM
  • Alrighty.  Let me ask a side question - In my problem above, I'm downloading the same xap (of type ListOfThingsWidget : IWidget) multiple times.  That's probably not necessary, is it? I should, once I have that xap, just reuse it to instantiate multiple copies of the UserControl it encapuslates, right?  Or no?

    Friday, April 29, 2011 6:26 PM
  • Well, I'm embarrassed to say what the problem turned out to be..

    I have a method that gets called before all this.  In that method I call a websevice to get the address of the widget xap I need to download.  The problem was that I was always adding a new OnCompleted event handler to THAT webservice call, which caused everything to stack up, of course.

    Bah, sorry for the noise, but thanks again for your time + responses Jeremy.

    Friday, April 29, 2011 7:30 PM