Registering implementations from dynamically loaded assemblies

Apr 15, 2012 at 8:10 AM

I ran into this problem earlier and haven't found a solution (or relevant info online).  I need to load an assembly at runtime and register one of its implementation with an existing interface:

            Assembly assembly = Assembly.LoadFrom("CMFramework.Content.InjectedDemo.dll");
            var types = assembly.GetExportedTypes().Where(type => typeof(IDemoRegionViewModel).IsAssignableFrom(type));

            foreach (Type type in types)
                 _unityContainer.RegisterType(typeof(IDemoShellViewModel), type);

When it tries to register the loaded implementation it throws this error:

The type CMFramework.Content.InjectedDemo.DemoRegionInjectedViewModel cannot be assigned to variables of type CMFramework.Infrastructure.IContent.Demo.IDemoShellViewModel.
Parameter name: from

What doesn't make sense is the retrieved implementations have been confirmed as being assignable to the IDemoRegionViewModel inteface, but Unity is still throwing the error.

I've cleaned my project, ensured that the assemblies are up to date, and ensured that there is a reference in the CMFramework.Content.InjectedDemo project to the project containing the IDemoShellViewModel interface.

 

 

Apr 15, 2012 at 10:45 PM

It would help if you posted a class hierarchy (slimmed down if appropriate) to demonstrate the problem.  

Could it be you have a mismatch between querying for IDemoRegionViewModel and then trying to assign a mapping from IDemoShellViewModel?

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Apr 15, 2012 at 11:19 PM

I'm not sure what you mean by a "mismatch between querying for IDemoRegionViewModel and then trying to assign a mapping from IDemoShellViewModel" - could you please elaborate?

Here are the class definitions:

namespace CMFramework.Infrastructure.IContent.Demo
{
    /// <summary>
    /// The interface for the demo region view model.
    /// </summary>
    public interface IDemoRegionViewModel : IVmContext
    {
        /// <summary>
        /// The bindable text property for showing the view model type.
        /// </summary>
        string ViewModelTypeText { get; set; }
    }
}

namespace CMFramework.Infrastructure.IContent
{
    /// <summary>
    /// The interface for the view model context.
    /// </summary>
    public interface IVmContext
    {
        /// <summary>
        /// The context.
        /// </summary>
        object VmContext { get; set; }
    }
}

namespace CMFramework.Content.InjectedDemo
{
    public class DemoRegionInjectedViewModel : ScreenBase, IDemoRegionViewModel
    {
        private string _viewModelTypeText;

        /// <summary>
        /// The bindable text property for showing the view model type.
        /// </summary>
        public string ViewModelTypeText
        {
            get { return _viewModelTypeText; }
            set
            {
                _viewModelTypeText = value;
                NotifyOfPropertyChange(() => ViewModelTypeText);
            }
        }
    }
}

Apr 15, 2012 at 11:25 PM
Edited Apr 15, 2012 at 11:25 PM

And here is the ScreenBase (slimmed down) for the DemoRegionInjectedViewModel:


namespace CMFramework.Infrastructure
{
    /// <summary>
    /// The screen base class.
    /// </summary>
    public class ScreenBase : Screen
    {
        protected bool _areDependenciesInjected = false; // Flag indicating initial DI status.

        protected object _view;  // The attached view.
        protected IDialog _dialog;  // The dialog service instance.
        protected ILogger _logger;  // The log service instance.
        protected IUnityContainer _unityContainer;  // The Unity container instance.
        protected ISettings _settings; // The application settings instance.
        protected IWindowManager _windowManager; // The window manager instance.
        protected IViewMappings _viewMappings; // The view mappings instance.
        protected List<IViewMapping> _bindableViewMappings; // The view mappings which are bindable to the derived screen.

        protected object _vmContext; // The view model context.

        public ScreenBase()
        {
            this.BuildUp(); // Inject all dependencies.
...
        }

        /// <summary>
        /// Dependency property that stores the Unity container and resolves common services.
        /// </summary>
        [Dependency]
        public virtual IUnityContainer UnityContainer
        {
            set
            {
                if (_areDependenciesInjected) return;

                _unityContainer = value;
                _dialog = _unityContainer.Resolve<IDialog>();
                _logger = _unityContainer.Resolve<ILogger>(new ParameterOverrides { { "name", this.GetType().FullName } });
                _settings = _unityContainer.Resolve<ISettings>();
                _windowManager = _unityContainer.Resolve<IWindowManager>();
                _viewMappings = _unityContainer.Resolve<IViewMappings>();
                this.UpdateBindableViewMappings();

                _logger.Log("Injected IUnityContainer into " + this.GetType().FullName, Category.Debug);

                _areDependenciesInjected = true;
            }
        }

        /// <summary>
        /// The view model context.
        /// </summary>
        public object VmContext
        {
            get
            {
                return _vmContext; 
            }
            set
            {
                _vmContext = value;
            }
        }
...
    }
}

Apr 15, 2012 at 11:46 PM

Wow I can't believe I missed what the problem was.  I had the wrong interface listed.  I blame the full blown cold I've had the last few days.

The code should have been this:

            Assembly assembly = Assembly.LoadFrom("CMFramework.Content.InjectedDemo.dll");
            var types = assembly.GetExportedTypes().Where(type => typeof(IDemoRegionViewModel).IsAssignableFrom(type));

            foreach (Type type in types)
                 _unityContainer.RegisterType(typeof(IDemoRegionViewModel), type);

Thanks for your input anyway, randylevy.

Apr 16, 2012 at 12:08 AM
Edited Apr 25, 2012 at 7:05 AM

> I'm not sure what you mean by a "mismatch between querying for IDemoRegionViewModel and then trying to assign a mapping from IDemoShellViewModel" - could you please elaborate?

What I meant was that the code is asking for all types that are of type IDemoRegionViewModel.  Then it's telling Unity that if anyone asks for a type IDemoShellViewModel to return a type of IDemoRegionViewModel.  It's not clear to me that all IDemoRegionViewModel's are also necessarily IDemoShellViewModel's.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com