• Blog
  • Info Support
  • Career
  • Training
  • International Group
  • Info Support
  • Blog
  • Career
  • Training
  • International Group
  • Search
logo InfoSupport
  • Latest blogs
  • Popular blogs
  • Experts
      • Alles
      • Bloggers
      • Speakers
  • Meet us
  • About us
    • nl
    • en
    • .NET
    • Advanced Analytics
    • Agile
    • Akka
    • Alexa
    • Algorithms
    • Api's
    • Architectuur
    • Artificial Intelligence
    • ATDD
    • Augmented Reality
    • AWS
    • Azure
    • Big Data
    • Blockchain
    • Business Intelligence
    • Cloud
    • Code Combat
    • Cognitive Services
    • Communicatie
    • Containers
    • Continuous Delivery
    • CQRS
    • Cyber Security
    • Dapr
    • Data
    • Data & Analystics
    • Data Science
    • Data Warehousing
    • Databricks
    • DevOps
    • Digital Days
    • Docker
    • eHealth
    • Enterprise Architecture
    • Hacking
    • Infrastructure & Hosting
    • Innovatie
    • Integration
    • Internet of Things
    • Java
    • Machine Learning
    • Microservices
    • Microsoft
    • Microsoft Bot Framework
    • Microsoft Data Platform
    • Mobile Development
    • Mutation Testing
    • Open source
    • Pepper
    • Power BI
    • Privacy & Ethiek
    • Python
    • Quality Assistance & Test
    • Quality Assurance & Test
    • Requirements Management
    • Scala
    • Scratch
    • Security
    • SharePoint
    • Software Architecture
    • Software development
    • Software Factory
    • SQL Server
    • SSL
    • Start-up
    • Startup thinking
    • Stryker
    • Test Quality
    • Testing
    • TLS
    • TypeScript
    • Various
    • Web Development
    • Web-scale IT
    • Xamarin
    • Alles
    • Bloggers
    • Speakers
Home » Configuring MEF with Linq To Xml Part 2: Making MEF recomposition on the fly when the file is edited
  • Configuring MEF with Linq To Xml Part 2: Making MEF recomposition on the fly when the file is edited

    • By Alex van Beek
    • Various 12 years ago
    • Various 0 comments
    • Various Various
    Configuring MEF with Linq To Xml Part 2: Making MEF recomposition on the fly when the file is edited

    In this post I assume you have read my first post on this subject. You can find the first post here. In the first part of this blog post, I explained briefly what MEF is and I showed how you can extend MEF with a custom ExportProvider, so that instead of configuring your exports with attributes, you could configure your exports with a XML file. The advantage of using a XML file over using attributes is that the application doesn’t need to be recompiled when your exports change. But when you change your XML file, the application may need to restart, or you could poll the file for any changes. In this post I’m going to show how you can make use of MEF’s recomposition features to recomposition on the fly when the content of the configuration XML file is changed. 

    MEF Recomposition

    Well, what is MEF recomposition? Take a look the the following code snippet:

       1: [Import(AllowRecomposition=true, AllowDefault=true)]

       2: public IGreeter Greeter

       3: {

       4:     set

       5:     {

       6:         _greeter = value;

       7:     }

       8: }

    If you’ve read my first blog post, all of this should be familiar, except the “AllowRecomposition=true” and the “AllowDefault=true”. The latter just means that when MEF can not find a suitable export to match this import, it will inject null instead of throwing an exception. I’ll come back the “AllowRecomposition” part in a minute. First take a look at the following code snippet:

       1: static void Main(string[] args)

       2:        {

       3:            var container = new CompositionContainer(new LinqToXMLExportProvider(@"....exports.xml"));

       4:            Printer p = new Printer();

       5:            container.ComposeParts(p);

       6:            p.Print();

       7:            Console.WriteLine("Change the export configuration file and press a key!!!!!");

       8:            Console.ReadKey();

       9:            p.Print();

      10:            Console.ReadKey();

      11:        }

    This should also be pretty familiar. Let’s go back to the “AllowRecomposition=true” part. When MEF is asked to satisfy all the imports of the Printer object on line 5, it records that the imports of the Printer object has been satisfied and MEF keeps a reference to the Printer object around thanks to the “AllowRecomposition=true” option specified on the Import attribute. When the exports change, MEF can now automatically satisfy the imports of the printer object again using the new exports. This happens automatically and you don’t have to call ComposeParts() again. When the configuration file is changed when hitting line 8 and after pressing a key, the second Print method should display something different based on how the configuration file was changed. Let’s take a look at how the LinqToXmlExportProvider class was enhanced to make this all possible. 

    LinqToXmlExportProvider

       1: public  class LinqToXMLExportProvider : ExportProvider

       2:     {

       3:         //Key is the contract name, value is the assembly qualified name of the implementing class....

       4:         private Dictionary<string, string> _mappings;

       5:         private FileSystemWatcher _watcher;

       6:&nbsp; 

       7:         public LinqToXMLExportProvider(string mappingFile)

       8:         {

       9:             _mappings = ParseFile(mappingFile);

      10:             _watcher = new FileSystemWatcher(Path.GetDirectoryName(mappingFile), Path.GetFileName(mappingFile));

      11:             _watcher.Changed += new FileSystemEventHandler(_watcher_Changed);

      12:             _watcher.NotifyFilter = NotifyFilters.LastWrite;

      13:             _watcher.EnableRaisingEvents = true;

      14:             

      15:         }

      16:&nbsp; 

      17:         void _watcher_Changed(object sender, FileSystemEventArgs e)

      18:         {

      19:             Dictionary<string, string> newMappings = ParseFile(e.FullPath);

      20:&nbsp; 

      21:             //Get the keys that are new in the export file....

      22:             List<ExportDefinition> newDefinitions = newMappings.Keys.Except(_mappings.Keys).Select(

      23:                 (key)=>CreateExportDefintion(key)).ToList();

      24:             //Get the keys that are removed in the export file

      25:             List<ExportDefinition> removedDefinitions = _mappings.Keys.Except(newMappings.Keys).Select(

      26:                 (key) => CreateExportDefintion(key)).ToList();

      27:&nbsp; 

      28:            // find the keys that may have changed values in the export file....

      29:             var result = from oldKV in _mappings

      30:                          join newKV in newMappings on oldKV.Key equals newKV.Key

      31:                          select new {OldKeyValue = oldKV, NewKeyValue = newKV};

      32:             foreach (var item in result)

      33:             {

      34:                 if(item.OldKeyValue.Value != item.NewKeyValue.Value)

      35:                 {

      36:                     //If keys have changed value, the contract is both added and removed...

      37:                     newDefinitions.Add(CreateExportDefintion(item.NewKeyValue.Key));

      38:                     removedDefinitions.Add(CreateExportDefintion(item.OldKeyValue.Key));

      39:                 }

      40:          

      41:             }

      42:&nbsp; 

      43:             _mappings = newMappings;

      44:             using (AtomicComposition atomic = new AtomicComposition())

      45:             {

      46:                 OnExportsChanging(new ExportsChangeEventArgs(newDefinitions, removedDefinitions,  atomic));

      47:                 atomic.Complete();

      48:             }

      49:             OnExportsChanged(new ExportsChangeEventArgs(newDefinitions, removedDefinitions, null));

      50:         }

      51:&nbsp; 

      52:&nbsp; 

      53:         private ExportDefinition CreateExportDefintion(string contractName)

      54:         {

      55:             Dictionary<string, object> metaData = new Dictionary<string, object>();

      56:             metaData.Add(CompositionConstants.ExportTypeIdentityMetadataName, contractName);

      57:             return new ExportDefinition(contractName, metaData);

      58:         }

      59:&nbsp; 

      60:         private Dictionary<string, string> ParseFile(string mappingFile)

      61:         {

      62:             XElement mappings = XElement.Load(mappingFile);

      63:             return mappings.Elements().ToDictionary((el)=> el.Attribute("contract").Value,

      64:                 (el=>el.Attribute("type").Value));

      65:         }

      66:&nbsp; 

      67:         protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)

      68:         {

      69:      

      70:             List<Export> exports = new List<Export>();

      71:             string implementingType;

      72:             if (_mappings.TryGetValue(definition.ContractName, out implementingType))

      73:             {

      74:                 Type t = Type.GetType(implementingType);

      75:                 object instance = t.GetConstructor(Type.EmptyTypes).Invoke(null);

      76:                 ExportDefinition exportDefintion = new ExportDefinition(definition.ContractName, new Dictionary<string, object>());

      77:                 Export toAdd = new Export(exportDefintion, () => instance);

      78:                 exports.Add(toAdd);

      79:             }

      80:             return exports;

      81:         }

    Most of this class was covered in my first blog post, so I&rsquo;ll only cover the additions to this class:

    • Line 5: I need to keep an eye on the XML configuration file and get notified when it changes. I use the FileSystemWatcher class for this.
    • Lines 10-13: This is the instantiation and configuring of the FileSystemWatcher. I&rsquo;m not interested in all the events, only when the content of the file changes.
    • Lines 17-50: This is the method where it all happens. This method is responsible for handle the event when the configuration file changes and it needs to notify MEF of the changed exports. Let&rsquo;s take a look at it in more detail:
      • Line 19: First thing to do when the file changes is to parse the file again into a new Dictionary of contractnames with implementing classes.
      • Lines 22-26: I need to find out which contracts were removed (properties of classes with imports of these contracts need to be set to null) and I need to find out which contracts were added, so that imports that previously were injected with null can now be satisfied with a value. I use the LINQ Except() method to accomplish this. I immediately create ExportDefinitions out of these contracts using the CreateExportDefinition() method. We&rsquo;re skipping a few lines to take a look at this method next.
      • Lines 53-58: The CreateExportDefinition() method, it takes a contractname and creates an ExportDefinition for it. An ExportDefinition contains a contractname and metadata. It took me a while to figure it out, but for the recomposition to work the metadata has to have at least one key / value pair. The key is the constant string defined in the “CompositionConstants.ExportTypeIdentityMetadataName&rdquo; variable and the value is simply the contractname. It&rsquo;s of great importance that this key / value pair is present in the metadata or else you can spend your whole day debugging wondering why nothing is happening :).
      • Lines 28-31: I also need to find the contractnames that were present in both old exports and the new exports. I do this by joining the old mappings with the new mappings (LINQ&rsquo;s standard join is an inner join).
      • Lines 31-41: Iterating over the joined mappings to find out if the implementing class belonging to the contractname has changed. If so, it&rsquo;s both added to the removed and the added collections.
      • Lines 44-48: To let MEF know that the Exports have changed and it needs to recomposition, I need to fire the ExportsChanging event of the ExportProvider. I can use the inherited OnExportsChanging method for this on line 46. This method accepts an ExportChangeEventArgs that needs two IEnumerables, one of the removed exports and one of the added exports.&nbsp; You can see that the call to the OnExportsChanging() method is wrapped in an AtomicComposition in a using statement. You can compare the AtomicComposition to the TransactionScope class. Recompositioning happens in a transaction and can be rolled back using the AtomicComposition object. When everything went ok, you call the Complete() method.
      • Line 49: After everything went ok you can fire the ExportsChanged event. This isn&rsquo;t really needed for recomposition but maybe your application wants to notify the user that the functionality of your application has changed. To make this possible you need to fire the ExportsChanged event by using the inherited OnExportsChanged method, supplying the same arguments as to the OnExportsChanging() method. Since this event does nothing for recomposition, it doesn&rsquo;t need a transaction and null is supplied for the AtomicComposition.&nbsp;

    Concluding

    Well, that’s it! This is all that is needed to let your custom ExportProvider know to MEF that recomposition is needed. Just imagine the possibilities, automatically recompositioning when you receive an email or a message from a message queue, they are endless. You can find a full working solution of the code above, here.

    Share this

Alex van Beek

View profile

IT Training at Info Support

Which training fits you?

Consultancy

Consultancy

Related blogs

  • Video Conferencing en OBS Studio koppelen: online prese…

    Video Conferencing en OBS Studio koppelen: online prese… Maaike Brouwer - 1 year ago

  • Verantwoordelijkheid pakken in jouw eigen persoonlijke …

    Verantwoordelijkheid pakken in jouw eigen persoonlijke … Stephan Versteegh - 1 year ago

  • Tips voor als je gaat afstuderen

    Tips voor als je gaat afstuderen Bart Renders - 2 years ago

Related downloads

  • Beslisboom voor een rechtmatig ‘kopietje productie’

  • Klantreferentie: Remmicom zet wetgeving om in intellige…

  • Klantreferentie RDW: Samenwerken voor veilig en vertrou…

  • Klantreferentie BeFrank: Strategische IT voor een innov…

  • Wie durft te experimenteren met data in de zorg?

Related videos

  • mijnverzekeringenopeenrij.nl

    mijnverzekeringenopeenrij.nl

  • Winnaar | Innovation Projects 2017

    Winnaar | Innovation Projects 2017

  • Explore | Info Support & HAN & Poliskluis

    Explore | Info Support & HAN & Poliskluis

  • LifeApps bij HagaZiekenhuis

    LifeApps bij HagaZiekenhuis

  • Info Support | Bedrijfsfilm

    Info Support | Bedrijfsfilm

Nieuwsbrief

* verplichte velden

Contact

  • Head office NL
  • Kruisboog 42
  • 3905 TG Veenendaal
  • T +31 318 552020
  • Call
  • Mail
  • Directions
  • Head office BE
  • Generaal De Wittelaan 17
  • bus 30 2800 Mechelen
  • T +32 15 286370
  • Call
  • Mail
  • Directions

Follow us

  • Twitter
  • Facebook
  • Linkedin
  • Youtube

Newsletter

Sign in

Extra

  • Media Library
  • Disclaimer
  • Algemene voorwaarden
  • ISHBS Webmail
  • Extranet
Beheer cookie toestemming
Deze website maakt gebruik van Functionele en Analytische cookies voor website optimalisatie en statistieken.
Functioneel
Altijd actief
De technische opslag of toegang is strikt noodzakelijk voor het legitieme doel het gebruik mogelijk te maken van een specifieke dienst waarom de abonnee of gebruiker uitdrukkelijk heeft gevraagd, of met als enig doel de uitvoering van de transmissie van een communicatie over een elektronisch communicatienetwerk.
Voorkeuren
De technische opslag of toegang is noodzakelijk voor het legitieme doel voorkeuren op te slaan die niet door de abonnee of gebruiker zijn aangevraagd.
Statistieken
De technische opslag of toegang die uitsluitend voor statistische doeleinden wordt gebruikt. De technische opslag of toegang die uitsluitend wordt gebruikt voor anonieme statistische doeleinden. Zonder dagvaarding, vrijwillige naleving door uw Internet Service Provider, of aanvullende gegevens van een derde partij, kan informatie die alleen voor dit doel wordt opgeslagen of opgehaald gewoonlijk niet worden gebruikt om je te identificeren.
Marketing
De technische opslag of toegang is nodig om gebruikersprofielen op te stellen voor het verzenden van reclame, of om de gebruiker op een website of over verschillende websites te volgen voor soortgelijke marketingdoeleinden.
Beheer opties Beheer diensten Beheer leveranciers Lees meer over deze doeleinden
Voorkeuren
{title} {title} {title}