2

I am working on a program that will communicate with various pieces of hardware. Because of the varied nature of the items it communicates and controls, I need to have a different "driver" for each different piece of hardware. This made me think that MEF would be a great way to make those drivers as plugins that can be added even after the product has been released.

I've looked at a lot of examples of how to use MEF, but the question that I haven't been able to find an answer to is how to populate a MEF plugin with external data (eg. from a database). All the examples I can find have the "data" hard-coded into the assembly, like the following example:

[Export( typeof( IRule ) )]  
public class RuleInstance : IRule  
{
    public void DoIt() {}  

    public string Name  
    {  
        get { return "Rule Instance 3"; }  
    }

    public string Version  
    {  
        get { return "1.1.0.0"; }  
    }  

    public string Description  
    {  
        get { return "Some Rule Instance"; }  
    }  
}

What if I want Name, Version and Description to come from a database? How would I tell MEF where to get that information?

I may be missing something very obvious, but I don't know what it is.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
goodman
  • 547
  • 6
  • 12

2 Answers2

3

You would have to either pass the information to the plugin after it loaded via properties:

[Export( typeof( IRule ) )]  
public class RuleInstance : IRule  
{
    puliic void DoIt() 
    { }

    public string Name { get; set; }
}

public class Program
{
    [Import(typeof( IRule ))]
    public IRule instance { get; set; }

    public void Run()
    {
        // Load the assemblies here

        instance.Name = "Rule Instance 3";
    }             
}

Or the plugin could request the variables though a host interface. You can either pass the IHost instance through a property or though a constructor parameter, but constructor parameters are not simple with MEF. Here is through a property:

 [Export( typeof( IRule ) )]  
public class RuleInstance : IRule  
{
    puliic void DoIt() 
    { }

    public void Initialise()
    {
        // Load our name from the host, this cannot be done in the constructor
        string name = Host.GetName(/* some parameters? */)
    }


    public IHost Host { get; set; }
    public string Name { get; set; }
}

public interface IHost
{
    string GetName(/* some parameters? */);
}

public class Program : IHost
{
    [Import(typeof( IRule ))]
    public IRule instance { get; set; }

    public void Run()
    {
        // Load the assemblies here       

        // Make sure the plugins know where the host is...
        instance.Host = this;
    }             
}

You could also "Export" the database interface and "Import" it into any plugins that need database access...

Nicholas
  • 783
  • 2
  • 7
  • 25
Tim
  • 7,746
  • 3
  • 49
  • 83
  • Yea, those make sense. Those do seem rather simple. In your Host example, you used an "Initialize()" function. Does MEF always call that function if it exists in the exporting Composable Part? – goodman May 30 '10 at 21:40
  • 1
    @hjoelr No, MEF won't call that function automatically. You would have to call it from the host. You could also have the host be exported, import it from the plugins, and then implement the IPartImportsSatisfiedNotification interface on your plugins and have them do the initialization in the OnImportsSatisfied method. – Daniel Plaisted May 30 '10 at 22:23
1

You can always export individual values (through contract names), here's an example:

public class Configuration
{
  [Export("SomeValue")]
  public string SomeValue
  {
    get { /* return value from database perhaps? */ }
  }
}

[Export(typeof(IRule))]
public class RuleInstance : IRule
{
  [Import("SomeValue")]
  public string SomeValue { get; private set; }
}
Matthew Abbott
  • 60,571
  • 9
  • 104
  • 129