New Posts New Posts RSS Feed: Cocktail.ObjectManager MEF import error in dynamically loaded XAP
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Forum LockedCocktail.ObjectManager MEF import error in dynamically loaded XAP

 Post Reply Post Reply
Author
paul View Drop Down
Newbie
Newbie


Joined: 16-Sep-2010
Posts: 19
Post Options Post Options   Quote paul Quote  Post ReplyReply Direct Link To This Post Topic: Cocktail.ObjectManager MEF import error in dynamically loaded XAP
    Posted: 24-Mar-2012 at 3:05pm
I am trying to code a prototype project following Marcel's TempHire UOW example he sent me a few days ago but I am running up against a roadblock with my dynamically loaded XAP.

Currently I have a simple solution structure:

App.Core (main application shell project)
  - App.Core.Services (my UOW/Repository project)
  - App.Core.Model (my DF and EF entities)
App.Module1 (my dynamically loaded project)
  - App.Module1.Services (my UOW/Repository project for Module1)
  - App.Module1.Model (my DF and EF entities for Module1)

I am referencing a slightly newer version of Cocktail.SL.dll (v0.5) and a new Cocktail.Contrib.SL.dll I got from Marcel's sample. My app is SL5 as is my Cocktail.SL.dll but the Cocktail.Contrib.SL.dll is SL4. I don't have source to recompile the contrib library to SL5 but I assume it should reference fine in my SL5 app.

I am dynamically loading my Module1 XAP by calling Composition.AddXap, when it's completed I find its workspace and navigate to it.
        [ImportMany(AllowRecomposition = true)]
        public ObservableCollection<Lazy<IWorkspaceIModuleNameMetadata>> Workspaces { getset; }
        public IEnumerable<IResult> LoadModule(string name)
        {
            yield return Composition.AddXap(name + ".xap");
 
            var ws = Workspaces
                            .Where(w => w.Metadata.Name.Equals(name + ".ViewModels.HomeViewModel"))
                            .Select(w => w.Value)
                            .FirstOrDefault();
 
            if (ws != null)
                NavigateTo(ws).ToSequentialResult().Execute();
        }
    [Export(typeof(IWorkspace)), ExportMetadata("Name""App.Module1.ViewModels.HomeViewModel")]
    public class HomeViewModel : Conductor<IScreen>IDiscoverableViewModelIHandle<EntityChangedMessage>IWorkspace
From my main shell project I am able to import my UOW/Repository
        [ImportingConstructor]
        public ShellViewModel(IToolbarManager toolbar,
                              IShellRepositoryManager<IShellRepository> repositoryManager,
                              IAuthenticationService authenticationService)
Where I get into trouble is trying to import my Module1 UOW/Repository from App.Module1.ViewModels.HomeViewModel ctor.
        [ImportingConstructor]
        public HomeViewModel( IAppModule1RepositoryManager<IAppModule1Repository> repositoryManager,
                              IErrorHandler errorHandler, 
                              IDialogManager dialogManager,
                              IToolbarManager toolbar)
        {
This results in the following MEF error

System.ComponentModel.Composition Warning: 1 : The ComposablePartDefinition 'App.Module1.ViewModels.HomeViewModel' has been rejected. 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 == "App.Module1.Services.IAppModule1RepositoryManager(App.Module1.Services.IAppModule1Repository)") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "App.Module1.Services.IAppModule1RepositoryManager(App.Module1.Services.IAppModule1Repository)".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))', invalid exports may have been rejected.

My problem seems to be centered around my AppModule1RepositoryManager class. I get the above error when I base it off of ObjectManager.
    [Export(typeof(IAppModule1RepositoryManager<IAppModule1Repository>))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class AppModule1RepositoryManager : ObjectManager<GuidIAppModule1Repository>IAppModule1RepositoryManager<IAppModule1Repository>
If I get rid of the ObjectManager base, like so
    [Export(typeof(IAppModule1RepositoryManager<IAppModule1Repository>))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class AppModule1RepositoryManager : IAppModule1RepositoryManager<IAppModule1Repository>
My App.Module1 HomeViewModel ImportingConstructor works but the AppModule1RepositoryManager instance is basically empty without the ObjectManager.

I'm curious if I am missing something with the way I am dynamically loading my Module1 XAP that causes the ObjectManager to not import or is there a problem with having more than one imported ObjectManager?

Is there any sample code I could look at that touches on what I am trying to accomplish. Basically use Cocktail in a shell and dynamically loaded XAPs. Each XAP would be its own Caliburn workspace with many screens. Each screen would have its own UOW/Repository backed by each module's own EF/DevForce model.

Thanks...  -Paul

Back to Top
paul View Drop Down
Newbie
Newbie


Joined: 16-Sep-2010
Posts: 19
Post Options Post Options   Quote paul Quote  Post ReplyReply Direct Link To This Post Posted: 24-Mar-2012 at 3:35pm
I was able to get Visual Mefx working under SL5 and captured this screenshot. This is coming from my App.Module1.Services.AppModule1RepositoryManager class. I am not sure why the ObjectManager would throw up an import error. Actually I am not even sure if this dump is valid. Mefx is a little flaky. 


Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 25-Mar-2012 at 2:45am
Looks like you are missing an export for IAppModule1Repository. ObjectManager needs to create new instances of the type it is managing. For that it looks to MEF for an export of said type, in your case IAppModule1Repository. Also the CreationPolicy of the part must be Any or NonShared, because ObjectManager creates NonShared instances.
Back to Top
paul View Drop Down
Newbie
Newbie


Joined: 16-Sep-2010
Posts: 19
Post Options Post Options   Quote paul Quote  Post ReplyReply Direct Link To This Post Posted: 25-Mar-2012 at 7:20am
 Thanks for the early morning reply Marcel. I am exporting my IAppModule1Repository. All my AppModule1 UOW/Repository code is an exact copy of my shell's UOW/Repository code. The only difference is AppModule1 is a dynamically loaded XAP. My shell loads correctly with correct UOW/repository instances but the AppModule1 fails at MEF's ImportingConstructor on my App.Module1.ViewModels.HomeViewModel ctor.
        [ImportingConstructor]
        public HomeViewModel(IAppModule1RepositoryManager<IAppModule1Repository> repositoryManager,
                             IToolbarManager toolbar)
Here my main shell's App.ViewModels.ShellViewModel (this does work)
        [ImportingConstructor]
        public ShellViewModel(IToolbarManager toolbar,
                              IShellRepositoryManager<IShellRepository> repositoryManager,
                              IAuthenticationService authenticationService)

I did have my repository manager (inherits from ObjectManager) parts marked as Shared but I changed them to NonShared with the same failure results. I will note the TempHire sample has it marked as Shared but i'll assume it doesn't matter since you only have one UOW manager in the sample.


Here are my two UOW/repository classes so far, one for the shell and the other for AppModule1
    [Export(typeof(IShellRepository)), PartCreationPolicy(CreationPolicy.NonShared)]
    public class ShellRepository : UnitOfWorkIShellRepository
    {
        [ImportingConstructor]
        public ShellRepository( 
                    [Import(RequiredCreationPolicy = CreationPolicy.NonShared)] 
                        IEntityManagerProvider<AppEntities> entityManagerProvider)
                    : base(entityManagerProvider)
        {
        }
    }
    [Export(typeof(IShellRepositoryManager<IShellRepository>))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class ShellRepositoryManager : ObjectManager<GuidIShellRepository>IShellRepositoryManager<IShellRepository>
    {
        #region IShellRepositoryManager<T> Members
 
        public IShellRepository Get(Guid key)
        {
            return GetObject(key);
        }
 
        #endregion
 
    }


    [Export(typeof(IAppModule1Repository)), PartCreationPolicy(CreationPolicy.NonShared)]
    public class AppModule1Repository : UnitOfWorkIAppModule1Repository
    {
        [ImportingConstructor]
        public AppModule1Repository( 
                    [Import(RequiredCreationPolicy = CreationPolicy.NonShared)] 
                        IEntityManagerProvider<AppModule1Entities> entityManagerProvider)
                    : base(entityManagerProvider)
        {
        }
    }
    [Export(typeof(IAppModule1RepositoryManager<IAppModule1Repository>))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class AppModule1RepositoryManager : ObjectManager<GuidIAppModule1Repository>IAppModule1RepositoryManager<IAppModule1Repository>
    {
        #region IAppModule1RepositoryManager<T> Members
 
        public IAppModule1Repository Get(Guid key)
        {
            return GetObject(key);
        }
 
        #endregion
 
    }

Marcel, I am going to send you a private msg with the link to my prototype solution. Maybe you can see something I am missing. 

-Paul

Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 25-Mar-2012 at 9:32am
I'll take a look. I meant the repositories should be NonShared, not the repository managers. Repository managers you only want one of each.
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 26-Mar-2012 at 11:46am
Paul,
I took a quick look at your solution. You appear to be missing exports for your EntityManagerProviders. For example the following class has a dependency to IEntityManagerProvider<ModuleHrEmployeeEntities>, but I couldn't find a corresponding export anywhere in your solution.
    [Export(typeof(IHrEmployeeRepository)), PartCreationPolicy(CreationPolicy.NonShared)]
    public class HrEmployeeRepository : UnitOfWork, IHrEmployeeRepository
    {
        [ImportingConstructor]
        public HrEmployeeRepository( 
                    [Import(RequiredCreationPolicy = CreationPolicy.NonShared)] 
                        IEntityManagerProvider<ModuleHrEmployeeEntities> entityManagerProvider)//,
                    //[Import(AllowDefault = true)] 
                        //IPreLoader preLoader = null) 
                    : base(entityManagerProvider)
        {
        }
    }
On a side note, you seem to be mixing up repository and unit of work. You call the above a repository. That's not a repository, that's a unit of work. If you use unit of work, repositories are contained in a unit of work. The point of a unit of work is in essence, so that you can bring together a bunch of repositories that do not know about each other and have them participate in the same workflow (unit of work).


Edited by mgood - 26-Mar-2012 at 11:59am
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down