Dependency Question with Resolve and other assemblies

May 28, 2008 at 5:38 PM
I have a WinApp project that contains a MainForm and various user controls. There is a separate service provider library that is loaded dynamically via Unity configuration - a single named "providerContainer" is configured and loaded via:

        static IUnityContainer providerContainer;
        public static IUnityContainer ProviderContainer
        {
            get { return providerContainer; }
        }

                providerContainer = new UnityContainer()
                    .AddNewExtension<SimpleEventBrokerExtension>();
                UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
                section.Containers["providerContainer"].Configure(providerContainer);


The user controls are loaded with code as follows:

     Views.PersonListView.PersonListViewControl personListViewControl =
        Program.ProviderContainer.Resolve<Views.PersonListView.PersonListViewControl>();
     group.ControlContainer.Controls.Add(personListViewControl);

The Resolve() method worked great as it would resolve the [Dependency] attribute in the user control and inject the appropriate provider.

Now I've refactored things a bit more to introduce an MVP pattern with a presenter class for each view (user control). Since I plan on also providing a separate web UI, I placed the presenters into a separate assembly (from the WinApp) so it could be shared between the two UIs (i.e. "views"). This presenter layer, in turn, now has the reference to the IServices since it will manage the data retrieval, validation, and updates. Thus, the view portion (the user controls) simply need a [Dependency] on the the presenter to handle getting data.

The WinApp project (containing the user controls) now has a standard reference to the separate ("static", so to speak) Presenter assembly. The presenters in turn have [Dependency] attributes on the IServices. When the above code is called to Resolve() on the user control, I get an exception of not being able to find the Presenter...

PersonListViewControl.listBoxControl_SelectedIndexChanged() Resolution of the dependency failed, type = "PersonListViewControl", name = "". Exception message is: The current build operation (build key Build Key[WinApp.Views.PersonListView.PersonListViewControl, null]) failed: The value for the property "Presenter" could not be resolved. (Strategy type Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy, index 3)

My question is, do I need to do something to Unity to get it to work with the separate Presenter assembly? I expected that when I did a Resolve() on the control it would "flow" down through the [Dependency] for the Presenter on the control to the [Dependency] for the IService on the presenter.

Remember, before introducing the separate presenter assembly, everything in Unity was configured and working correctly.

Thanks,
John
May 29, 2008 at 3:19 AM
Edited May 29, 2008 at 3:20 AM
John,

You may want to check that your Presenter Class does not have a dependency that cannot be resolved by Unity which is why you are getting the error.

I got the same error attempting to duplicate your situation when I added a dependency to the Presenter Class that could not be resolved with Unity.

This code works:

    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();
            TestView view = container.Resolve<TestView>();
        }
    }

    public class TestView
    {
        [Dependency]
        public TestPresenter Presenter { get; set; }
    }

    public class TestPresenter
    {
    }

but when I add a constructor dependency to the Presenter Class that Unity cannot resolve I get an error very similar to yours:

    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();
            TestView view = container.Resolve<TestView>();
        }
    }

    public class TestView
    {
        [Dependency]
        public TestPresenter Presenter { get; set; }
    }

    public class TestPresenter
    {
        public TestPresenter(IServiceProvider provider)
        {
        }
    }

Not sure this is the reason for your error, but Unity exceptions can often be ambiguous and make you look in the wrong place for the problem.

Regards,

Dave

http://www.davidhayden.com/
Microsoft MVP C#

May 29, 2008 at 3:31 AM
Hi David,

Your suggestion lead me down a good path. Regarding the dependency...I tried to resolve it early to see if that would help. The Presenter only has a dependency on IServiceProvider. In Program.cs main[] right after I configured the container I forced it to resolve the IServiceProvider and everything worked. When the View is loaded, the dependency to the Presenter is resolved and in the Presenter the dependency to the IServiceProvider is also correctly resolved. I guess Unity has the IServiceProvider ready and can resolve it whereas before, it was looking for it when the first Presenter requested it (via [Dependency]) so it never could find/resolve it.

Can I "take away" from this that everything you put in the Container must be resolved/forced?

John


DavidHayden wrote:
John,

You may want to check that your Presenter Class does not have a dependency that cannot be resolved by Unity which is why you are getting the error.

I got the same error attempting to duplicate your situation when I added a dependency to the Presenter Class that could not be resolved with Unity.

This code works:

{{

    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();
            TestView view = container.Resolve<TestView>();
        }
    }

    public class TestView
    {
        [Dependency]
        public TestPresenter Presenter { get; set; }
    }

    public class TestPresenter
    {
    }
}}

but when I add a constructor dependency to the Presenter Class that Unity cannot resolve I get an error very similar to yours:

{{

    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();
            TestView view = container.Resolve<TestView>();
        }
    }

    public class TestView
    {
        [Dependency]
        public TestPresenter Presenter { get; set; }
    }

    public class TestPresenter
    {
        public TestPresenter(IServiceProvider provider)
        {
        }
    }
}}

Not sure this is the reason for your error, but Unity exceptions can often be ambiguous and make you look in the wrong place for the problem.

Regards,

Dave

[url:David Hayden|http://www.davidhayden.com/]
Microsoft MVP C#




May 29, 2008 at 4:21 PM

John,

You shouldn't need to resolve your dependency early. You will, however, need to register your type mapping.

If I take the non-working version of my code above and add a class that implements IServiceProvider and register the type mapping in Unity, all works fine.

    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();
            container.RegisterType<IServiceProvider, MyProvider>();
            TestView view = container.Resolve<TestView>();
        }
    }

    public class TestView
    {
        [Dependency]
        public TestPresenter Presenter { get; set; }
    }

    public class TestPresenter
    {
        public TestPresenter(IServiceProvider provider)
        {
        }
    }

    public class MyProvider : IServiceProvider
    {
        public object GetService(Type serviceType)
        {
            return null;
        }
    }

If you find yourself needing to resolve IServiceProvider beforehand, something isn't quite right.

Regards,

Dave

http://www.davidhayden.com/
Microsoft MVP C#

May 30, 2008 at 2:25 AM
Again, you're right. I removed those lines and it still works. It's probably as you said - if anything prevents a resolve and loading then it just seems to behave strangely. Thanks again for your help.

John

DavidHayden wrote:

John,

You shouldn't need to resolve your dependency early. You will, however, need to register your type mapping.

<snip>

If you find yourself needing to resolve IServiceProvider beforehand, something isn't quite right.

Regards,

Dave

http://www.davidhayden.com/
Microsoft MVP C#