I few months ago I took an old VB.NET Winforms up and modernized with WebMAP to ASP.NET Core and Angular. I added some new controllers, integrated swagger, hangfire and some other new stuff.
Everything was working fine and I jumped to some other projects.
After a few months I had to work again in this app. I just needed to add a couple of new controllers.
However I had some problems because I had forgotten a lot about the app, I did not remember all the dependencies in the DI container setup.
I thought that there should be a way to visualize all those dependencies. But sadly after a while I could not find one.
So I had to create one for myself.
In the end it was quite easy. I am posting this code in case you find this useful too.
To start, we need a reference to the IServiceCollection object. So if you have an ASP.NET Core app like me just go to your StartUp.cs file.
IServiceCollection _services; public void ConfigureServices(IServiceCollection services) { _services = services; // rest omitted }
Ok, now that you do that you just need to iterate through the service collection. Go to your Configure(IApplicationBuilder app,...) section in Startup.cs and add the following gist:
app.Map("/allservices", builder => builder.Run(async context => { var sb = new StringBuilder(); var dependencies = new Dictionary<string,string>(); sb.AppendLine("<pre>"); sb.AppendLine("digraph Services {"); var services = _services.Select(svc => svc.ServiceType.ToString()).ToHashSet(); foreach (var svc in _services) { var serviceName = svc.ServiceType.ToString(); var implementationName = svc.ImplementationType?.ToString(); if (implementationName != null) { var implDependencies = svc.ImplementationType.GetConstructors().SelectMany(cons => cons.GetParameters()).Select(p => p.ParameterType.ToString()).Distinct().Where(x => services.Contains(x)); if (implDependencies.Count() > 0) { // Register Constructor dependendencies foreach(var d in implDependencies) { dependencies.TryAdd(implementationName, d); } } } } Action<string, string, string, IEnumerable<string>> printGroup = (label, cluster, color, group) => { if (group.Count() > 0) { sb.AppendLine($" subgraph cluster_{cluster} {{"); sb.AppendLine(" style = filled;"); sb.AppendLine($" color = {color};"); sb.AppendLine(" node[style = filled, color = white];"); sb.AppendLine($" label = \"{label}\";"); foreach (var item in group) { sb.AppendLine($" \"{item}\""); } sb.AppendLine(" }"); } }; var scopedGroup = _services.Where(s => s.Lifetime == ServiceLifetime.Scoped).Select(s => s.ServiceType.ToString()); var transientGroup = _services.Where(s => s.Lifetime == ServiceLifetime.Transient).Select(s => s.ServiceType.ToString()); printGroup("scoped", "0", "blue", scopedGroup); printGroup("transient", "1", "lightgrey", transientGroup); // Make interfaces different sb.AppendLine(); sb.AppendLine(); sb.AppendLine(" node [color=green]"); var interfacesGroup = _services.Where(s => s.ServiceType.IsInterface).Select(s => s.ServiceType.ToString()); foreach (var @interface in interfacesGroup) { sb.AppendLine($" \"{@interface}\""); } sb.AppendLine(); sb.AppendLine(" node [color=black]"); var noninterfacesGroup = _services.Where(s => !s.ServiceType.IsInterface).Select(s => s.ServiceType.ToString()); foreach (var nonInterface in noninterfacesGroup) { sb.AppendLine($" \"{nonInterface}\""); } //Now print dependencies foreach (var d in dependencies) { sb.AppendLine($" \"{d.Key}\" -> \"{d.Value}\""); } sb.AppendLine("}"); sb.AppendLine("</pre>"); // Ok ready. Now return all the graph await context.Response.WriteAsync(sb.ToString()); }));
With that code in place you can browse to this url:
Ok now you can go to any website like:
And paste that graph definition:
Ok, I know it is a little rough but it only took a couple of hours. I hope it helps you if you ever need a way to visualize your DI dependencies like me.