We Are GAP Mobilize
Free Assessment Tool

Visualize DI dependencies in ASP.NET Core DI Container.

by Mauricio Rojas, on Apr 25, 2020 10:43:25 AM

 

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:

Screenshot of after the code is in place you should see this and can browse url

Ok now you can go to any website like:

And paste that graph definition:

Screenshot of how to paste the 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.

 

Topics:asp.net coreasp.netvb.net

Comments

Subscribe to Mobilize.Net Blog

More...

More...
FREE CODE ASSESSMENT TOOL