locked
MEF Parts containing Classes RRS feed

  • Question

  • I am developing an application using MEF and NET Framework4.7 using WPF and MVVM practices.  It has a Main Program, a DataAccessLayer and an open-ended set of modules in an MEF Module Directory.  The DAL is also in the ModuleLibrary.  The DAL contains the Data Classes for the application all of which conform to an IDataClass (Eg User, Customer, Account and so on). 

    It also contains generic methods such as Find<T>(ID), Load<T>(), Add<T>(entity) etc, the typical set, which are called from the Main Program and any module.  I am using ClickOnce to Publish.

    It all works fine so long as I put in a reference to the DAL wherever I want to use the generic methods, I can do calls Like Find<Account>(1234) BUT when I try injecting the DAL it falls apart since the contained classes cannot be in the MEF contract.

    I have tried various approaches but don't like any of them:-

     1 - Making the individual DataClasses Export as IDataClass and doing an ImportMany where needed.  No help as I cannot see how to get the TypeParameter <T> from the Imported class.

     2 - Making the calls Find(className) instead of Find<T>.  Just moves the problem to the DAL, again how could you convert he string to a TypeParameter even knowing the type.
          I have seen a very yucky solution using Reflection and dynamic calls, it looks as if it might work but there are likely to be a lot of data calls and I am not keen on taking the performance hit.

     3 - Keeping the direct references and somehow making sure the MEF modules are in the users Reference Path (eg the application directory in Programs).  Probably would work but rather defeats the object of MEF.

     4 - Dynamically adding to the Reference Path.  Too yucky to consider even if I could find the users Reference Path.

     5 - Compiling the DAL along with the Main Program.  Means I would have to reissue the program at any update and I am far from sure that the DAL is stable enough to deal with an open ended set of modules so I would like to keep it separate.

    It seems a problem that others of you out there may have come across.  There may even be a known good solution, but if so several days of searching have not found it.

    Solutions, suggestions or ideas welcome.


    This is some code to show the problem
       public class Bootstrapper  // pretty standard code
        {
            private CompositionContainer _container;
            public Program prog { get; set; }
            public void Run()
            {
                var catalog = new AggregateCatalog();
             
                string ModuleDirectory = @"c:\Users\John\Documents\MEFTest\ModuleLibrary\";  // Temp place for this
                Directory.CreateDirectory(ModuleDirectory);
                catalog.Catalogs.Add(new AssemblyCatalog(typeof(Bootstrapper).Assembly));
                catalog.Catalogs.Add(new DirectoryCatalog(ModuleDirectory));
                _container = new CompositionContainer(catalog);
                _container.ComposeParts(this);
                try
                {
                    prog = _container.GetExportedValue<Program>("MEFTest.Program");      // Get the main program from the Container
                }
                catch (Exception ex) {  } 
            }
        // The program to inject the DAL and use Find<T>
        [Export(typeof(Program))]
        public class Program
        {
               [Import(typeof(IDAL))]  // The data model and methods to access the data
               IDAL myDataModel { get;  }
            public void Run()
            {
                // DataAccess myDataModel = new DataAccess();  // Uncomment this and Comment out the Import, Reference the DAL and it all works fine
                User myUser = myDataModel.Find<User>(1234) as User;  // "Type or Namespace User cannot be found"
                string result = myUser.Text;
            }
        }
        // The DAL code
        [Export(typeof(IDAL))]
        public class DataAccess : IDAL
        {
            public DataAccess() { }
            public void Initialise(){  }
            public IDataClass Find<T>(int intID) where T : IDataClass
            {
                return new User();  // Normally goes off to the Database to get the entity
            }
            public void Add<T>(IDataClass Entity) where T : IDataClass
            { }  // Adds the entity to the Database
            //...etc...
        }
        // The user class (inside the DAL project)
        public class User : IDataClass
        {
            public string Text { get; set; }
            public User()
            { Text = "Found"; }
        }
        //  The Interfaces
        public interface IDAL
        {
            void Initialise();
            IDataClass Find<T>(int KeyID) where T : IDataClass;
            //...etc...
        }
        public interface IDataClass
        {
        }


    John Meers



    • Edited by JohnMeers Thursday, September 28, 2017 4:55 PM
    Tuesday, September 26, 2017 4:59 PM

All replies

  • Hi JohnMeers,

    Thank you for posting here.

    For your question, could you provide some simple code for us to test? According to your description, we could not have a good understanding for that. We are waiting for your update.

    Best Regards,

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, September 28, 2017 7:26 AM
  • I have edited it to add code to show the problem.  I think basically I expected injecting to replace referencing which it does not.  On the other hand everything is known at the solution compile time so maybe it could.

    I use MEF heavily elsewhere in the app with no problem but maybe I will have to abandon it for the DAL.


    John Meers


    • Edited by JohnMeers Thursday, September 28, 2017 5:06 PM
    Thursday, September 28, 2017 5:01 PM