• 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 » .Net 4.0: Configuring MEF with Linq to Xml
  • .Net 4.0: Configuring MEF with Linq to Xml

    • By Alex van Beek
    • .NET 12 years ago
    • .NET 0 comments
    • .NET .NET
    .Net 4.0: Configuring MEF with Linq to Xml

    MEF is kind of a dependency injection framework for .Net, I deliberately say “kind of”, because MEF is much more. To get an idea about what MEF does for you, take a look at the code below: 

       1: using System;

       2: using System.ComponentModel.Composition.Hosting;

       3: using InterfaceLibrary;

       4: using System.ComponentModel.Composition;

       5: using System.Reflection;

       6:  

       7: namespace ExtendingMEF

       8: {

       9:     class Printer

      10:     {

      11:         private IGreeter _greeter;

      12:         private ISayGoodNight _goodNighter;

      13:         private ISayGoodBye _goodByeSayer;

      14:  

      15:         [Import]

      16:         public ISayGoodBye GoodByer

      17:         {

      18:             set

      19:             {

      20:                 _goodByeSayer = value;

      21:             }

      22:         }

      23:  

      24:         [Import]

      25:         public IGreeter Greeter

      26:         {

      27:             set

      28:             {

      29:                 _greeter = value;

      30:             }

      31:         }

      32:  

      33:         [Import]

      34:         public ISayGoodNight SayGoodNight

      35:         {

      36:             set

      37:             {

      38:                 _goodNighter = value;

      39:             }

      40:         }

      41:  

      42:         public Printer()

      43:         {

      44:            

      45:             CompositionContainer c = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));

      46:             c.ComposeParts(this);           

      47:         }

      48:  

      49:  

      50:         public void Print()

      51:         {

      52:             Console.WriteLine(_greeter.Greet());

      53:             Console.WriteLine(_goodNighter.SayGoodNight());

      54:             Console.WriteLine(_goodByeSayer.SayGoodBye());

      55:         }

      56:  

      57:     }

      58: }

    You can see three properties of three different interface types. The idea is, that interfaces provide a very loose coupling between my Printer class and the classes implementing these interfaces, but somewhere in my code, the constructor of an implementing class must be called. This means that when I want to switch the implementing class, I need to change the constructor call. MEF removes this dependency between my class and an implementing class completely. It does this by injecting an instance of the implementing class into the properties. Because MEF does the injecting, I never have to call any constructor and the dependencies between my Printer class and any implementing classes are completely removed. The class responsible for the injecting is the CompositionContainer class. The injecting is happening on the lines 45 and 46. A CompositionContainer needs a ComposablePartCatalog, in this case the AssemblyCatalog. A catalog is in essence a catalog of classes that can be injected. MEF out of the box supports a couple of different catalogs, I’m using the AssemblyCatalog, which looks in the given Assembly for types that it can inject, but there is also a TypeCatalog and a DirectoryCatalog. The problem of these built in catalogs is that they rely on attributes in the source code for determining whether a type can be injected:

     

       1: using System;

       2: using System.Collections.Generic;

       3: using System.Linq;

       4: using System.Text;

       5: using InterfaceLibrary;

       6:  

       7: namespace ImplementationLibrary

       8: {

       9:     [Export("InterfaceLibrary.ISayGoodBye"]

      10:     public  class GoodByeSayer : ISayGoodBye

      11:     {

      12:  

      13:         #region ISayGoodBye Members

      14:  

      15:         public string SayGoodBye()

      16:         {

      17:             return "See you soon!";

      18:         }

      19:  

      20:         #endregion

      21:     }

      22: }

    This is the type that gets injected in the GoodByer property. When I call “c.ComposeParts(this)” on line 46, a couple of things happen:

    1. The supplied object’s (this) properties with the Import attribute are enumerated.
    2. A contractname is created, this is very important. Default with the import attribute, the contractname is the fully qualified type name of the property to which the Import attribute is applied. In this case for the Goodbyer property: “InterfaceLibrary.ISayGoodBye”.
    3. A search begins for a type which exports the same contractname. Where this search is performed is dependant on which type of catalog is used. When a type is found with an Export attribute with a matching contractname, an instance of this type is injected into the property. It is important to realize that the matching of imports with exports is purely based on strings and not interface types. It works with interface types because of the fully qualified name.

    A much heard criticism of the built in catalogs is this attribute based programming model. For the imports, it isn’t that bad, but for the exports it is. When I want to switch the implementation that is injected to an interface typed property, I need to change the Export attributes of the concrete types. Changing attributes, means recompiling. It would be nice if I could configure in an external file which types get injected. Luckily, MEF has some extensibility points. I could write a custom catalog and most people would do this. But in the newer versions of MEF (Visual Studio 2010 Beta 2), ExportProviders were introduced. With an export provider you can determine where and how is searched for classes that can be injected. I decided to create a  LinqToXmlExportProvider class, which uses an external XML file to determine which classes are exported and what their contractname is. This way I can get rid of the pesky Export attribute. First take a look at the external exports.XML file:

       1: <?xml version="1.0" encoding="utf-8" ?>

       2: <exports>

       3:   <export contract="InterfaceLibrary.IGreeter" type="ImplementationLibrary.HelloGreeter,ImplementationLibrary"/>

       4:   <export contract="InterfaceLibrary.ISayGoodNight" type="ImplementationLibrary.HelloGreeter,ImplementationLibrary"/>

       5:   <export contract="InterfaceLibrary.ISayGoodBye" type="ImplementationLibrary.GoodByeSayer,ImplementationLibrary"/>

       6: </exports>

    &nbsp;

    It’s a very simple file which just says to the ExportProvider: “if you&rsquo;re looking for a contractname of “InterfaceLibrary.IGreeter &rdquo;, “ImplementationLibrary.HelloGreeter,ImplementationLibrary&rdquo; is the type you can inject. This file replaces the Export attributes. Notice that to specify the type to inject, the assembly qualified name is used. Let&rsquo;s take a look at the class which parses this XML file and uses it to provide exports to MEF:

       1: using System;

       2: using System.Collections.Generic;

       3: using System.ComponentModel.Composition.Hosting;

       4: using System.ComponentModel.Composition.Primitives;

       5: using System.Linq;

       6: using System.Xml.Linq;

       7:&nbsp; 

       8: namespace ExtendingMEF

       9: {

      10:     class LinqToXMLExportProvider : ExportProvider

      11:     {

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

      13:         private Dictionary<string, string> _mappings;

      14:&nbsp; 

      15:         public LinqToXMLExportProvider(string mappingFile)

      16:         {

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

      18:             _mappings = mappings.Elements().ToDictionary((el)=> el.Attribute("contract").Value,

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

      20:             

      21:         }

      22:&nbsp; 

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

      24:         {

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

      26:             string implementingType;

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

      28:             {

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

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

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

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

      33:                 exports.Add(toAdd);

      34:             }

      35:             return exports;

      36:         }

      37:&nbsp; 

      38:        

      39:     }

      40: }

    &nbsp;

    I&rsquo;m going to cover the important parts:

    • Line 15 &ndash; 21: This is the constructor. It get&rsquo;s the location of the file and parses it using Linq to Xml into a Dictionary. The contractname is the key and the type of which an instance can be injected is the value. This allows me to easily give MEF an instance to inject when MEF gives me a contractname.
    • Line 23 &ndash; 36: This is the heart of the class and where it all happens. When MEF finds a property with the Import attribute , it creates an ImportDefinition. In this definition, the contractname and optionally metadata is saved. The GetExportsCore() method is called by MEF and MEF supplies an ImportDefinition. It is my task to give MEF according to this ImportDefinition, an IEnumerable of exports (read: instances that can be injected) that match the ImportDefinition, in this case, that match the contractname. This the responsibility of the GetExportsCore() method.
    • Line 27: I&rsquo;m checking whether the XML file provided a type to inject according to the contractname.
    • Line 29-30: If I have found a type belonging to the supplied contractname, I instantiate it using reflection and the default constructor.
    • Line 31: If an ImportDefinition is the ImportAttribute, you can see the ExportDefinition as the Export attribute. An ExportDefinition contains information about the exported type, normally this is taken from the Export attribute, but in my case from the XML file. This information is the exported contractname and possibly some metadata. I don&rsquo;t use metadata so I just supply an empty Dictionary.
    • line 33: an Export object combines an ExportDefinition with an actual instance of the type the ExportDefinition belongs to. The Export object is added to the list and finally returned. Notice that MEF supports injecting of IEnumerables when multiple types can satisfy an import. I don&rsquo;t support this, so my returned IEnumerable always contains one item, or it is empty when no class can be found that satisfies the ImportDefinition.

    That&rsquo;s it, that is all there is to it. Using this ExportProvider is easy, just supply it to the constructor of the CompositionContainer:

       1: public Printer()

       2: {

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

       4:     c.ComposeParts(this);           

       5: }

    &nbsp;

    Now I only have to change the XML file to determine which type gets injected when MEF gives me a contractname, so I can switch the implementing type of the GoodByer property and all the other interface based properties, without recompiling :). You can find a working sample project here.

    Share this

Alex van Beek

View profile

Related IT training

Go to training website

Related Consultancy solutions

Go to infosupport.com

Related blogs

  • Innovative patterns in software quality management

    Innovative patterns in software quality management Tom van den Berg - 1 month ago

  • Developing a Service Fabric service using another host

    Developing a Service Fabric service using another host Tim van de Lockand - 5 months ago

  • Adding a package to your private WinGet.RestSource feed…

    Adding a package to your private WinGet.RestSource feed… Léon Bouquiet - 10 months 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}