Bootstrapping Unity - Composition Root location

霸气de小男生 提交于 2019-11-28 11:51:24
Marcus Höglund

Like this great answer said

"All components in an application should be composed as late as possible"

And by that you should compose them in the global.asax in the WebApp project. All of them (which basically answers the two questions).

The composition root is a place where all of the modules in your application get composed. In your case the WebApp will be that project and should therefore refer to all of the projects in your solution. The WebApp should refer to Business Layer, XYZ and all of the other projects that you add.

"However, that would cause a circular dependency.."

No, only the composition root refers to the projects in the solution.

But how does business layer and XYZ work with each other then?

They don't. The core principle of DIP is to be dependent of abstractions and to fully use the DIP in your solution you need to design the code correctly.

Let's say we have one class in business Layer project that have a dependecy on the XYZ project

using XYZ;
namespace BusinessLayer
{
    public class businessData
    {
        public int GetData()
        {
            var data = new XYZData(); //from the XYZ project
            return data
        }
    }
}

And this class in the XYZ project

namespace XYZ
{
    public class XYZData
    {
        public int GetData()
        {
            return 1;
        }
    }
}

Now we have the dependecy between the project BusinessLayer and XYZ. To solve this we need to make the businessData in the BusinessLayer depend on abstraction instead of details.

To do that we need to use Interfaces to get rid of the dependency between the classes and when that's taken care of we don't need the reference of XYZ in the BusinessLayer project as it's not in use anymore.

But where do we store the Interface?

For this you create a ModelProject which all projects in the solution will refer to. The ModelProject do not refer to anything as it's purpose is to only store the DTOs and Interfaces etc.

The references in the solution should then be as this (sorry for my paint skillz):

Where WebApp, being the composition root, should refer to all projects in the solution. The rest of the projects should only refer to ModelProject

To resolve the dependecy in businessData add this interface to the Modelproject

namespace Modelproject
{
    public interface IXYZData
    {
        int GetData();
    }
}

And then the implementation of the interface in the classes

For Business project

using Modelproject;
namespace BusinessLayer
{
    public class businessData
    {
        private IXYZData _data;
        public businessData(IXYZData data)
        {
            this._data = data;
        }

        public int GetData()
        {
            return _data.GetData();
        }
    }
}

And for XYZ project

using Modelproject;
namespace XYZ
{
    public class XYZData: IXYZData
    {
        public int GetData()
        {
            return 1;
        }
    }
}

Then in the global.asax in the WebApp you resolve the Interface IXYZData with the XYZData class. By Unity that would be

var container = new UnityContainer();
container.RegisterType<IXYZData, XYZData>(new HierarchicalLifetimeManager());
GlobalConfiguration.Configuration.DependencyResolver = new UnityResolver(container);

Hope this helps, cheers

Update:

If you want to use the businessData class in another class you should apply the same structure as we did on the XYZData class which is adding an Interface.

namespace Modelproject
{
    public interface IbusinessData
    {
        int GetData();
    }
}

Then add the interface inheritage to the class

using Modelproject;
namespace BusinessLayer
{
    public class businessData: IbusinessData
    {
    .....

And finally tell the Unity container in Global.asax to resolve the interface to the class

container.RegisterType<IbusinessData, businessData>(new HierarchicalLifetimeManager());

Now, in every class that you need to use the IbusinessData, add it in the constructor of the class like we did in the businessData constructor and then Unity will make sure to inject all dependencies when that class is being created at runtime.

  1. You should do this once in Startup method
  2. You can implement Unity Dependency resolver and dont do code like container.Resolve<IDependency>()

You can read a really good article about it here https://www.asp.net/web-api/overview/advanced/dependency-injection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!