Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PRISM + MEF -- How to specify which export to use?

Basically, how can I specify which of my implementations to choose from?

FooService.cs:

public interface IFooService
{
    Int32 GetFoo();
}

[Export(typeof(IFooService))]
public sealed class Foo100 : IFooService
{
    public Int32 GetFoo()
    {
        return 100;
    }
}


[Export(typeof(IFooService))]
public sealed class Foo200 : IFooService
{
    public Int32 GetFoo()
    {
        return 200;
    }
}

ClientViewModel.cs:

[Export()]
public class ClientViewModel : NotificationObject
{
    [Import()]
    private IFooService FooSvc { get; set; }

    public Int32 FooNumber
    {
        get { return FooSvc.GetFoo(); }
    }
}

Boostrapper.cs:

public sealed class ClientBootstrapper : MefBootstrapper
{
    protected override void ConfigureAggregateCatalog()
    {
        base.ConfigureAggregateCatalog();

        //Add the executing assembly to the catalog.
        AggregateCatalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
    }

    protected override DependencyObject CreateShell()
    {
        return Container.GetExportedValue<ClientShell>();
    }

    protected override void InitializeShell()
    {
        base.InitializeShell();

        Application.Current.MainWindow = (Window)Shell;
        Application.Current.MainWindow.Show();
    }
}

ClientShell.xaml.cs:

[Export()]
public partial class ClientShell : Window
{
    [Import()]
    public ClientViewModel ViewModel
    {
        get
        {
            return DataContext as ClientViewModel;
        }
        private set
        {
            DataContext = value;
        }
    }

    public ClientShell()
    {
        InitializeComponent();
    }
}

I'm not sure where to go from here for setting up my app to inject the correct one (in this case, I want Foo100 to be injected. I know I can just let them export as themselves and specify a Foo100 instead of an IFooService, but is that the correct way?

like image 861
michael Avatar asked Mar 01 '11 21:03

michael


2 Answers

I don't think you can specify in MEF that you want your singleton import bound only to the Foo200 implementation.

You can either declare your import property as an IEnumerable and then you can enumerate through the selections to pick out which one you want to use in your own code, or you can make sure that the two implementations of IFooSvc reside in different assemblies and that only one of those assemblies is included when you're defining your MEF catalog.

like image 26
dthorpe Avatar answered Oct 30 '22 22:10

dthorpe


If there are more than one exports with a certain contract then you will have to either import them all (by declaring a property of a collection type with the ImportMany attribute on it) or make the contracts more specific by specifying a name for the contract:

[Export("Foo100", typeof(IFooService))]
public sealed class Foo100 : IFooService
{
    public Int32 GetFoo()
    {
        return 100;
    }
}


[Export("Foo200", typeof(IFooService))]
public sealed class Foo200 : IFooService
{
    public Int32 GetFoo()
    {
        return 200;
    }
}

-

[Import("Foo100", typeof(IFooService)]
private IFooService FooSvc { get; set; }
like image 186
Pavlo Glazkov Avatar answered Oct 30 '22 22:10

Pavlo Glazkov