Property Import

Feb 4, 2011 at 4:59 AM

Hi,

I am trying to perform a property import like this,

ILoggerService

{

void SomeFunction();

}

 

[Export(Typeof(ILoggerService))]

public class LoggerService:ILoggerService

{

// do some logging stuff

void SomeFunction(){}

}

class A

{

[Import]

public ILoggerService loggerservice

{ get;set;}

public A()

{

loggerservice.SomeFunction() // This fails always as my loggerservic is always NULL!!

}

}

Am I missing something? Another question, at what point "loggerservice" gets intialized for property import? (Unlike constructor import where I import contract implementation during construction).

 

regards,

Indro

Feb 4, 2011 at 2:50 PM

[Export(Typeof(ILoggerService))] ... this should not even compile, but I will assume that this is just a typo and the real code is

[Export(typeof(ILoggerService))]

You can also use constructor import with MEF.

public class MyClass 
{ 
   [ImportingConstructor] 
   public MyClass(IMyregisteredExport exported) { } 
}

The one thing that I notice in particular is that you have made no reference to your MEF Host, are you for example doing the following anywhere in your application

var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(this);

Feb 7, 2011 at 3:44 AM

Hey Bill,

Thanks for your reply. Let me put it this way, I am trying use property import in Prism based app. I have tried using Importing Constructor which works perfectly fine, but I am unable get my property import concept correct.

I have posted a small section of my code. Please spent few moments glancing through this.

// Custom bootstrapper class

 public partial class MyBootstrapper : MefBootstrapper
    {
       protected override DependencyObject CreateShell() { // returns shell }
       protected override void  InitializeShell() {// inti shell }  

       protected override void ConfigureAggregateCatalog() {
            this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()));
            this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog((typeof(MyModuleOne).Assembly)));  }

        protected override void ConfigureContainer() { base.ConfigureContainer(); }    
    }

Now my little MyModuleOne has this,

   [ModuleExport(typeof(MyModuleOne))]
    public class MyModuleOne : IModule
    {
        [Import]
        public MyService myservice { get; set; } // This is the service I want to property import

            
        public void Initialize() { myservice.DoSomething; }
    }

Now Service class is,

[Export]

public class MyService { Public MyService() {// default constructor etc} // Function DoSomething }

Now I am unable get the 'myservice' populated. It always returning me NULL!!

Am I missing something obvious. Can anyone throw light on property import concept from Prism view point.

 

Thanks in advance.

Regards,

Indro

Feb 7, 2011 at 3:19 PM
Edited Feb 7, 2011 at 3:21 PM

I created two projects.
 
1. CodeplexExampleModule -ClassLibrary
to this module I added the following references
 Microsoft.Practices.Prism
 Microsoft.Practices.Prism.MefExtensions
 System.ComponentModel.Composition

2. CodeplexExamples - WPF Application
to this module I added the following references
 Microsoft.Practices.Prism
 Microsoft.Practices.Prism.MefExtensions
 System.ComponentModel.Composition
 CodeplexExampleModule

To the CodeplexExampleModule project I added a single file called Class1, and in that file I wrote the following

using System;
using System.ComponentModel.Composition;
using Microsoft.Practices.Prism.MefExtensions.Modularity;
using Microsoft.Practices.Prism.Modularity;

namespace CodeplexExampleModule
{
    [ModuleExport(typeof(MyModule))]
    public class MyModule : IModule
    {
        [Import]
        public Lazy<IMyService> ServiceRef { get; set; }

        public void Initialize() { ServiceRef.Value.DoSomething(); }
    }

    public interface IMyService { void DoSomething(); }
    
    [Export(typeof(IMyService))]
    public class MyService : IMyService
    {
        public void DoSomething() { var x = true; }
    }
}

I then turned to the CodeplexExamples project, where I removed the StartupUri from App.xaml, and in the code-behind I wrote

 protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            var bootstrapper = new Bootstrapper();
            bootstrapper.Run();
        }

I next created a Bootstrapper class file, into which I wrote

using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System.Windows;
using CodeplexExampleModule;
using Microsoft.Practices.Prism.MefExtensions;

namespace CodeplexExamples
{
    public class Bootstrapper : MefBootstrapper
    {
        protected override DependencyObject CreateShell()
        {
            return new MainWindow();
        }

        protected override void ConfigureAggregateCatalog()
        {
            base.ConfigureAggregateCatalog();
            AggregateCatalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(MyModule).Assembly));
        }
    }
}

I then set CodeplexExamples to be my startup project, hit F5 and my breakpoint at this line

public void DoSomething() { var x = true; }

was hit. This was my sanity check to make sure we are not missing out anything really simple. So, armed with the knowledge that all works aas intended, I then set about figuring out what the differences are, and most importantly, what is the main difference between your posting and mine.

1.  base.ConfigureAggregateCatalog();  ... this line is absent from your ConfigureAggregateCatalog implementation
  As it turns out, this omission is not of major importance in this instance.

2. [Import]
    public Lazy<IMyService> ServiceRef { get; set; }

 Importing your service, you do not make use of Lazy<T>. Again this is not of much import, because Lazy<T> only means that the class will not be instantiated unless the property's accessors are used.

  
3. [Export(typeof(IMyService))]
    public class MyService : IMyService

 Your service implementation does not implement an interface, and is exported without the typeof() expression. So, changed my service implementation to read as follows

 [Export]
    public class MyService 
    {
        public void DoSomething()
        {
            
        }
    }

and my module implementation
  [ModuleExport(typeof(MyModule))]
    public class MyModule : IModule
    {
        [Import]
        public MyService ServiceRef { get; set; }

        public void Initialize()
        {
            ServiceRef.DoSomething();
        }
    }

Unfortunately I cannot reproduce your problem.

Feb 8, 2011 at 4:08 AM

Hello Bill,

Thanks for such a detailed answer. Example looks delightfully simple:).

Let me do a braindump to find out a RC.

Thanks again.

Indro