Introduction
Developer 1: Hey I want to make some changes to CommonLibrary1. Is that going to affect the 15 other projects people are working on?
Developer 2: I dunno, ask John.
Developer 1: He told me to ask you.
Sound familiar? I wanted a quick easy, foolproof way to visualize project dependencies without depending on human intervention, i.e. some poor sap typing stuff into a Word document which would probably be wrong before he saved the document.
This project attempts to solve that by taking a directory location and an output JPG location as parameters. It then scans the directories getting all the *.csproj files and determines their relationships. It then uses the graphviz package to visualize these dependencies quickly and easily with fancy schmancy arrows and circles.
Background
I thought for sure that someone would have done this already but I could only find something similar for C++ apps. Even if there was an existing thing that did this, chances are it wouldn't work for the code structure I like to use. Different companies like to do their references and what not differently, so it would be nice to own the code and modify it according to personal preference... hence this project was born.
I like to put in post build events for code that will copy the output DLLs to a directory called References. That way, whether it is a debug or release compile, the referencing projects all point to the same place and everyone has consistent references. This project assumes that structure so if you have something different then you will need to make code changes. Don't worry, I have included 3 sample projects and full unit tests so you can figure out how it's supposed to work first, then change it to suit your needs. You'll need Nunit to run the tests. It's free, get it.
Using the Code
In the DependencyTracker/Launch directory, there is a *.bat file which will generate two JPG files: one for the library code projects only and one that generates a JPG for all projects. By changing the search directory and output JPG locations, you can customize it to your scenario and then schedule it to run on whatever schedule works best. Output to a network drive which happens to be on a Web server and you have instant up to date documentation which is easily accessible.
Most of the magic happens in Project.cs when it is trying to find the references:
private string[] GetReferenceProjectPaths()
{
XmlDocument project = new XmlDocument();
project.Load(ProjectPath);
XmlNamespaceManager namespaceManager =
new XmlNamespaceManager(project.NameTable);
namespaceManager.AddNamespace(
"ns",
"http://schemas.microsoft.com/developer/msbuild/2003");
Nothing earth shattering, just parsing the *.csproj file which is XML and looking for the references. The only complication is that the reference is stored as a relative file path, but by changing the current directory to where the project is and then just browsing to that path, we can get to the referenced DLL pretty easy. Then we just have to figure out where the source project is given the compiled DLL's location. As mentioned previously, I like to keep a consistent "References" folder so it isn't too difficult to find the referenced project file from there. If you have a different structure, you will need to make changes here.
After all of this is loaded in memory, we then call out to a command line program to launch the graphviz image generation based on a file that is output below. We must recursively parse all the various projects and dependencies that have been loaded and take care not to process the same one twice so we don't get phantom arrows on the graph. The basic format of the graphviz program is to take a *.dot file which has lines like "a -> b
" which means a
points to b
.
private void AppendProjectLinks(StringBuilder sb, ProjectList projects)
{
foreach (Project project in projects)
foreach (Project reference in project.ReferencedProjects)
{
if (!ProcessedLinks.Contains(
project.Name + "-" + reference.Name)
)
{
sb.Append(
"\"" + project.Name + "\" -> \"" +
reference.Name + "\"" + Environment.NewLine
);
ProcessedLinks.Add(project.Name + "-" + reference.Name);
}
AppendProjectLinks(sb, project.ReferencedProjects);
}
}
Points of Interest
All the tests use relative paths so it shouldn't matter where you unzip the files to, they should work as long as you don't move any of the folders around in the zip file.
History
- 17-August-2007 - Initial version
- 04-September-2007 - Changed dot.exe launch method to use registry key
I've been a software developer since 1996 and have enjoyed C# since 2003. I have a Bachelor's degree in Computer Science and for some reason, a Master's degree in Business Administration. I currently do software development contracting/consulting.