views:

35

answers:

2

I'm sorry if this question has already been asked 100 times, but I'm really struggling to get it to work.

Say I have have three projects.

  • Core.dll
    • Has common interfaces
  • Shell.exe
    • Loads all modules in assembly folder.
    • References Core.dll
  • ModuleA.dll
    • Exports Name, Version of module.
    • References Core.dll

Shell.exe has a [Export] that contains an single instance of a third party application that I need to inject into all loaded modules.

So far the code that I have in Shell.exe is:

static void Main(string[] args)
{
        ThirdPartyApp map = new ThirdPartyApp();

        var ad = new AssemblyCatalog(Assembly.GetExecutingAssembly());
        var dircatalog = new DirectoryCatalog(".");
        var a = new AggregateCatalog(dircatalog, ad);

        // Not to sure what to do here.
}

class Test
{
    [Export(typeof(ThirdPartyApp))]
    public ThirdPartyApp Instance { get; set; }

    [Import(typeof(IModule))]
    public IModule Module { get; set; }
}

I need to create a instance of Test, and load Instance with map from the Main method then load the Module from ModuleA.dll that is in the executing directory then [Import] Instance into the loaded module.

In ModuleA I have a class like this:

[Export(IModule)]
class Module : IModule
{
    [Import(ThirdPartyApp)]
    public ThirdPartyApp Instance {get;set;}
}

I know I'm half way there I just don't know how to put it all together, mainly with loading up test with a instance of map from Main.

Could anyone help me with this.

A: 

I seem to be able to get it to work this way, in the constructor of the Test class(yes I know not to do work in the constructor, I will move it out):

public Test()
    {
        ThirdPartyApp map = new ThirdPartyApp();
        this.MapInfoInstance = map;

        //What directory to look for!
        String strPath = AssemblyDirectory;
        using (var Catalog = new AggregateCatalog())
        {
            DirectoryCatalog directorywatcher = new DirectoryCatalog(strPath, "*.dll");
            Catalog.Catalogs.Add(directorywatcher);
            CompositionBatch batch = new CompositionBatch();
            batch.AddPart(this);
            CompositionContainer container = new CompositionContainer(Catalog);
            //get all the exports and load them into the appropriate list tagged with the importmany
            container.Compose(batch);

            foreach (var part in Catalog.Parts)
            {
                container.SatisfyImportsOnce(part);
            }
        }

        Module.Run();
    }
Nathan W
A: 

Your main method should probably look like this:

static void Main(string[] args)
{   
    var exeCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
    var dircatalog = new DirectoryCatalog(".");
    var aggregateCatalog = new AggregateCatalog(exeCatalog, dirCatalog);
    var container = new CompositionContainer(aggregateCatalog);
    var program = container.GetExportedValue<Program>();

    program.Run();
}

To make an instance of the ThirdPartyApp class available as a part that can be imported by your modules, you have two options. The first is to explicitly add such an instance to the container with the ComposeExportedValue extension method like this:

container.ComposeExportedValue<ThirdPartyApp>(new ThirdPartyApp());

Alternatively, you can export it via a property by having a class like this one:

public class ThirdPartyAppExporter
{
    private readonly ThirdPartyApp thirdPartyApp = new ThirdPartyApp();

    [Export]
    public ThirdPartyApp ThirdPartyApp { get { return thirdPartyApp; } }
}
Wim Coenen