Prism module system from within WCF service?
Asked Answered
D

3

7

Can you boostrap a Prism module system from within the WCF service? Because no matter what I do my MEF dependencies are not being fulfilled.

E.g.:

This is my WCF service implementation

public class MyService : IMyServiceContract{
    // This should get filled by MEF after Prism loads the required modules
    [Import]
    IDatabase db;

    public MyService(){
        var bootsrapper = new MyServiceBoostrapper();
        bootsrapper.Run();
    }
}

This is my Prism boostrapper with MEF flavor:

public class MyServiceBoostrapper : MefBootstrapper
{
    protected override void ConfigureContainer()
    {
        base.ConfigureContainer();
    }

    protected override IModuleCatalog CreateModuleCatalog()
    {
        return new ConfigurationModuleCatalog();
    }
    protected override void ConfigureAggregateCatalog()
    {
        base.ConfigureAggregateCatalog();

        // TODO: Add this assembly ... don't know why
        this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(MyServiceBoostrapper).Assembly));
        this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(IDatabase).Assembly));
        // This is what provides the service
        this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(DatabaseImpl).Assembly));
    }

    protected override DependencyObject CreateShell()
    {
        // we don't need the shell
        return null;
    }

}

Here is my module that contains the interfaces for Database Prism service :

[ModuleExport(typeof(IDatabase))]
public class ModuleActivator : IModule
{
    public void Initialize()
    {
        // Do nothing as this module simply provides the API.
    }
}
public interface IDatabase
{
  // interface methods here ...
}

and lastly here is the Prism database service itself:

[ModuleExport(typeof(DatabaseImpl), DependsOnModuleNames = new string[] { "IDatabase" })]
public class ModuleActivator : IModule
{
    public void Initialize()
    {
        // Do nothing as this is a library module.
    }
}

[Export(typeof(IDatabase))]
public class DatabaseImpl : IDatabase
{
   /// implementation here ...
}

Tried this for the last few hours with no success. My db import is always null and is never initialized.

Note, that everything works if I do all of this without Prism, but only with MEF.

Doehne answered 24/5, 2013 at 19:35 Comment(5)
So what about the progress on this issue?Gabby
I think I found a solution in the book "Dependency Injection in .NET" (Part 3, Ch. 7.3). Still testing it out. Basically it's just a matter of hooking into the WCF startup routine.Doehne
Like I said in my comment. I really think its a problem of Configuring your container and regisering the types...Gabby
Can I ask why you are using PRISM? According to the documentation PRISM provides guidance to implementing rich client-side user interfaces. I understand you may wish to compose your service instance using a DI container - but not sure why you wish to do it using PRISM. Do you really want a reference to WindowsBase in your assembly that defines your service?Bringingup
Their wording here, near beginning of the page "Even single-person projects can realize the benefits by creating more testable and maintainable applications that can evolve over time using the modular approach" made me think Prism could be used as a module system. I think I am beginning to realize that it's not really as generic as I thought.Doehne
D
0

Well, it seems like the solution is not to use Prism at all, as it does not add anything "modular" with it's modules. It seems like the modules are concepts purely for visual applications.

Instead, one has to hook into the WCF "startup" procedure and boostrap the MEF container from there. The answer on how to do this is rather involved (though not complicated), as WCF already has many extension/hook-in points.

The answer I used lies in the book Dependency Injection in .NET by Mark Seemann in Chapter 7.3: "Composing WCF applications".

Short of copying the whole chapter from that book into this answer, I'm afraid that's the best I can do.

Doehne answered 3/6, 2013 at 3:40 Comment(0)
L
3

You won't have anything imported to your db field because the MyService object is not created by the container - it can't be created by it because the container is actually being created in the bootstrapper, which is in MyService's constructor.

One simple way to solve this is to satisfy your object's imports after the container is initialized. To do so, you can expose the container in the bootstrapper like so:

public class MyServiceBoostrapper
{
    public CompositionContainer MyServiceContainer
    {
        get { return Container; }
    }

    // Rest of bootstrapper definitions...
}

Then modify MyService's constructor:

public MyService()
{
    var bootsrapper = new MyServiceBoostrapper();
    bootsrapper.Run();

    // This is an extension method. You'll need to add
    // System.ComponentModel.Composition to your using statements.
    bootstrapper.MyServiceContainer.SatisfyImportsOnce(this);

    // At this stage, "db" should not be null.
}
Lehrer answered 1/6, 2013 at 21:1 Comment(2)
Yea that works. Thanks. Of course the thing is, I didn't even need Prism. It was just confusing the issue. Also, reading the Dependency Injection in .NET book helped clarify what was done where. Especially their example of how to bootstrap WCF. I'm too tired today to write that answer here, but that would be the correct way to bootstrap a WCF service.Doehne
Yeah, Prism is probably not necessary here, but I thought explaining why things didn't work would help you to make a better decision on how to bootstrap your service while also allowing you to keep your current implementation. Anyway, hope my answer was of some help.Lehrer
G
1

I'm not sure that the following snippets will help you. I have only experiance with PRISM and Unity. Just try it and tell me what's happening.

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

        this.RegisterTypeIfMissing(typeof(IDatabase), typeof(DatabaseImpl ), true);
    }

You are also creating and empty ModuleCatalog and never configure it.

protected override void ConfigureModuleCatalog()
        {

            base.ConfigureModuleCatalog();

            var moduleCatalog = (ModuleCatalog)ModuleCatalog;

            Type Initial = typeof(ModuleActivator);
            moduleCatalog.AddModule(new ModuleInfo
            {
                ModuleName = Initial.Name,
                ModuleType = Initial.AssemblyQualifiedName
            });
        }
Gabby answered 27/5, 2013 at 13:54 Comment(0)
D
0

Well, it seems like the solution is not to use Prism at all, as it does not add anything "modular" with it's modules. It seems like the modules are concepts purely for visual applications.

Instead, one has to hook into the WCF "startup" procedure and boostrap the MEF container from there. The answer on how to do this is rather involved (though not complicated), as WCF already has many extension/hook-in points.

The answer I used lies in the book Dependency Injection in .NET by Mark Seemann in Chapter 7.3: "Composing WCF applications".

Short of copying the whole chapter from that book into this answer, I'm afraid that's the best I can do.

Doehne answered 3/6, 2013 at 3:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.