How instantiate a service in MefBoostrapper during Application startup

Topics: Prism v4 - WPF 4
Oct 23, 2013 at 7:44 AM
How to instantiate an Application specific Service/Object (like mapping service) during the application startup using container.GetExportedValues<>( ) or another method in MefBoostrapper and in which method should this code reside.
Thanks in advance
Oct 23, 2013 at 2:08 PM
Yes. I would do that. Would rather use Container.GetExportedValue<>() if you are expecting just 1 value.
Oct 23, 2013 at 7:10 PM
Hi jivara,

Before you instantiate a specific service, you would need to register it to the container. In order to do this, you would declare an export attribute on the service to register the assembly on the bootstrapper. You may achieve this with the following implementation:
[Export(typeof(IMyService))]
public class MyService : IMyService
{
...
}
public partial class MyBootstrapper : MefBootstrapper
{
    protected override void ConfigureAggregateCatalog()
    {
           this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(IMyService).Assembly));
    }
...
}
Then, you could instantiate the service inside a module initialize() method for example, by calling it from the container or the ServiceLocator, which could be injected in the constructor.


I hope this helps,

Gabriel Ostrowsky
https://blogs.southworks.net/gostrowsky
Oct 23, 2013 at 9:02 PM
Hi Gabriel,
Thanks for your helpful answer, but i'm seeking something else. The point is that I was searching for using AutoMapper as a shared service, then I found one good solution which need to put the following code in the application startup (MefBootstrapper in my case) in order to fetch all instances of that interface in the container and call the CreateMappings method on them:
 var mappings = this.Container.GetExportedValues<IMappingCreator>();
            foreach (IMappingCreator mc in mappings)
            {
                mc.CreateMappings();
            }
if I put this code in each module IModule implementation I have to repeat same code for each module plus there are some views displayed at startup using view discovery approach which need mapping of data and in this case mapping is not working. So I need to add the above code in MefBootstrapper but I don't know where
Thanks
Oct 24, 2013 at 6:57 AM
You could put your implementations of IMappingCreator in a single assembly and put them in a folder. And then you can use the DirectoryCatalog to load the dlls from the directory into the AggregateCatalog. So your mapping implementations will be something like
[Export(typeof(IMappingCreator))]
public class Mapper1 : IMappingCreator {}

[Export(typeof(IMappingCreator))]
public class Mapper2 : IMappingCreator {}
Say you put them in a directory called Mappers under your bin folder, then you can load these into the AggregateCatalog like below
AggregateCatalog.Catalogs.Add(new DirectoryCatalog(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Mappers")));
And then you can do what you have mentioned above in the bootstrapper.
Oct 24, 2013 at 1:40 PM
Hi gan_s,
I have a class in each Module that implements IMappingCreator interface so I don't have to add a new project for mapping. so the question still persisting where to put the aforementioned code in the MefBootStrapper and how to initialize it before the module are intitialized because modules depend on it
Thanks.
Oct 24, 2013 at 2:09 PM
Hi jivara,

Does your shell/main project have a reference to your modules?
Oct 24, 2013 at 2:49 PM
Hi gan_s
Yes the Shell has references to the module and they are added to the catalog in ConfigureAggregateCatalog() method. Something else I want to make clear that previously I put the creation of mapping classes in the initialize() method of each module but I had to duplicate code between modules and the views that were discovered and displayed during startup was missing the mapping.
Oct 24, 2013 at 3:54 PM
Hi Jivara,

Based on the Mef Bootstrapper's run() implementation, I believe you could initialize the mapping services inside the CreateShell() method, right before creating the Shell View. Taking into account that Module Initialization comes after Shell creation in the Bootstrapper, you would have created every mapping for any View without needing to create them on each module's initialize() method again.

The aforemention approach would look like the following implementation. By the time the CreateShell() method is called, the Container would have already got created:
protected override DependencyObject CreateShell()
{
      var mappings = this.Container.GetExportedValues<IMappingCreator>();
      foreach (IMappingCreator mc in mappings)
      {
           mc.CreateMappings();
      }
      return this.Container.GetExportedValue<Shell>();
}
I hope this helped you,

Gabriel Ostrowsky
http://blogs.southworks.net/gostrowsky
Oct 24, 2013 at 4:46 PM
Hi Gabriel ,
You know what? it's exactly the same solution I came up with, but I thought there is a standard approach for such cases for example a built in method called by bootstrapper that can be overridden to contain application specific code required in such cases.
Thanks for your help