MEF and WCF

MEF and WCF

Old forum URL: forums.lhotka.net/forums/t/10040.aspx


mattruma posted on Monday, February 07, 2011

I am using MEF successfully with CSLA to inject my data access layer ... this allows me to do mocking without hitting the database. Working great ... thank you CSLAContrib!

So I have the following projects:

Up to this point ... my tests pass with fly colors! Now I added 2 more projects:

This where my tests start breaking down ... for some reason the data access in the data project is not being load automatically. I can manually assign the container, like I do in the test project, but my concerns are:

Has anyone else ran into these issues? In some case I wish I could just "tell" the IOC what to load, maybe a configuration setting.

Any help would be much appreciated!

mattruma replied on Monday, February 07, 2011

This is the error I get ...

The composition remains unchanged. The changes were rejected because of the following error(s): The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.

1) No valid exports were found that match the constraint '((exportDefinition.ContractName == "MyProject.Business.Repository.ICustomerDataFactory") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "MyProject.Business.Repository.ICustomerDataFactory".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))', invalid exports may have been rejected.

Resulting in: Cannot set import 'MyProject.Business.Customer.DataFactory (ContractName="MyProject.Business.Repository.ICustomerDataFactory")' on part 'MyProject.Business.Customer'.

Element: MyProject.Business.Customer.DataFactory (ContractName="MyProject.Business.Repository.ICustomerDataFactory") -->  MyProject.Business.Customerrn"} System.Exception {System.ComponentModel.Composition.ChangeRejectedException}

JonnyBee replied on Monday, February 07, 2011

There's a load of different ways to load Exports into the container (ex: folders, assembly names, explicitly).

I assume that the IoC container is intialized OK but some/all Exports are not being registered.

1. Verify that the assemblies containing your exports are present in the folder where your tests are running.

2. Check which Exports gets loaded into the IoC container.

mattruma replied on Monday, February 07, 2011

I'll do this ...

I did create a Windows Forms application and referenced the CSLAContrib.MEF, MyProject.Business and MyProject.Data  -- same references as the wcf service -- and everything works.

JonnyBee replied on Monday, February 07, 2011

Look at the Hosting part documentation here

http://msdn.microsoft.com/en-us/library/system.componentmodel.composition.hosting.aspx

This shows the possible classes to use for loading Exports.

mattruma replied on Monday, February 07, 2011

When the MEFBusinessBase calls the inject the _container is NOT NULL, which it should be ... no? and is when I run it from my tests that do not interact with the WCF Service.

mattruma replied on Monday, February 07, 2011

Looks like when it first runs it is null, but no DLLs are loaded ... maybe because I am making a project reference to the data and business from the service?

Once I am done with my testing I have to restart IIS otherwise the _container is still considered initialized.

mattruma replied on Monday, February 07, 2011

How would you explicitly tell it what assembly to load? Is it already built in to the CSLAContrib.MEF library?

mattruma replied on Monday, February 07, 2011

The dlls do exist in the bin directory, but for some reason they are not being registered ... wondering if it has something to do with it being a web application with .svc at one level and the dlls in the bin directory.

mattruma replied on Monday, February 07, 2011

It has to be a WEB issue ... I created a WebMvc application to work with the business and data layers just like the WCF service AND the Windows Forms application. The only one that works is the WIndows Forms application.

JonnyBee replied on Monday, February 07, 2011

Hi Matt,

Try and change the initialization of IoC to this code (will add assemblies bin folder if present)

    public static CompositionContainer Container
    {
      get
      {
        //create and configure container if one does not yet exist
        if (_container == null)
        {
          lock (_syncRoot)
          {
            if (_container == null)
            {
              Debug.Write("Start configuring MEF Container");

              //create container
              var catalog = new AggregateCatalog();
              //catalog.Catalogs.Add(new DirectoryCatalog(Assembly.GetCallingAssembly().Location));
              catalog.Catalogs.Add(new DirectoryCatalog("."));
              var dirInfo = new System.IO.DirectoryInfo(@"bin");
              if (dirInfo.Exists) 
                catalog.Catalogs.Add(new DirectoryCatalog(@".\bin\."));
              catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
              _container = new CompositionContainer(catalog);
              _container.ComposeParts();

              Debug.Write("End configuring MEF Container");
            }
          }
        }
        return _container;
      }
    }

 

mattruma replied on Monday, February 07, 2011

Hi Jonny ... that didn't seem to work ... it doesn't seem to be able to find the root directory, it goes to C:\. So I added a setting in my config file for a "Plugins" directory ... that seems to work, just not as elegant as I would have liked it to be.

        /// <summary>
        /// Gets the container.
        /// </summary>
        public static CompositionContainer Container
        {
            get
            {
                //create and configure container if one does not yet exist
                if (_container == null)
                {
                    lock (_syncRoot)
                    {
                        if (_container == null)
                        {
                            //create container
                            var catalog = new AggregateCatalog();

                            catalog.Catalogs.Add(new DirectoryCatalog("."));

                            var dirInfo = new DirectoryInfo(ConfigurationManager.AppSettings["PluginsFolder"]);

                            if (dirInfo.Exists)
                            {
                                catalog.Catalogs.Add(new DirectoryCatalog(
                                    string.Format("{0}."ConfigurationManager.AppSettings["PluginsFolder"])));
                            }

                            catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));

                            _container = new CompositionContainer(catalog);

                            _container.ComposeParts();
                        }
                    }
                }
                return _container;
            }
        }

Copyright (c) Marimer LLC