views:

104

answers:

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.

Thanks! Joel

+1  A: 

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...

Tim
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?
hjoelr
@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
+1  A: 

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