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.