It is undeniable that some of the best packages that are in any C# developer’s arsenal is created by the community.

Just like any other developer that likes developing in his spare, I find myself testing around stuff and experimenting with ideas to see what might work. I recently starting sticking with a very specific project which I think has potential. This is my first project that went beyond the scale I expected it to code wise.

It is a project coded in .NET Core 2.1 with C#. What I really like about .NET Core is that there is an out of the box IoC system that anyone can jump right in and enjoy the benefits of dependency injection.

However, as I already mentioned, my project got out of hand and I ended up with a lot (A LOT) of interfaces and classes implementing those interfaces. This in return made my dependency registration really lengthy on my Startup.cs file. This is what the dependency registration looks like.

services.AddSingleton<IRepositoryOne, RepositoryOne>();  
services.AddSingleton<IRepositoryTwo, RepositoryTwo>();  
services.AddSingleton<IRepositoryThree, RepositoryThree>();  
...
services.AddScoped<IServiceOneHundrend, ServiceOneHundrend>();  

You can see how, even though this isn’t technically a problem, can make my OCD go haywire.

Introducing Scrutor

Scrutor (Scrutor — I search or examine thoroughly; I probe, investigate or scrutinise) is a Nuget package made by Kristian Hellang. It offers assembly scanning and decoration extensions for .NET Core’s Dependency Injection. I will focus on the scanning side of things even though the decoration part of it is also very interesting.

This is what the code above would look like with Scrutor.

services.Scan(scan => scan  
  // We start out with all types in the assembly of IAssemblyMarker
  .FromAssemblyOf<IAssemblyMarker>()
  // AddClasses starts out with all public, non-abstract types in this assembly.
  // These types are then filtered by the delegate passed to the method.
  // In this case, we filter out only the classes that are assignable to IRepository.
  .AddClasses(classes => classes.AssignableTo<IRepository>())
  // We then specify what type we want to register these classes as.
  // In this case, we want to register the types as all of its implemented interfaces.
  // So if a type implements 3 interfaces; A, B, C, we'd end up with three separate registrations.
  .AsImplementedInterfaces()
  // And lastly, we specify the lifetime of these registrations.
  .WithSingletonLifetime()
  .AddClasses(classes => classes.AssignableTo<IService>())
  .AsImplementedInterfaces()
  .WithScopedLifetime());

(IAssemblyMarker is an empty interface at the top level of the project. It will guide Scrutor into which assembly it has to scan)

That’s all there is. You can add more and more repositories, services, mappers and validator and as long as you have them registered with the base interfaces Scrutor will automatically scan the assemblies and register the dependencies with the appropriate lifetimes.

You can download Scrutor from Nuget using:

Install-Package Scrutor  
or  
dotnet add package Scrutor  

Scrutor is Open Source under the MIT license.
Github link: https://github.com/khellang/Scrutor

Disclaimer: I am not affiliated with Scrutor in any way.