• Stars
    star
    234
  • Rank 171,630 (Top 4 %)
  • Language
    C#
  • License
    MIT License
  • Created over 6 years ago
  • Updated 9 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Extension method to find/register classes in an assembly into the Microsoft DI provider

NetCore.AutoRegisterDi

This NuGet library contains an extension method to scan an assemby and register all the non-generic public classes (see excluded class types) against their implemented interfaces(s) into the Microsoft.Extensions.DependencyInjection dependency injection provider.

Version 2.0.0 update: New attributes for defining the ServiceLifetime of your classes, e.g. adding the [RegisterAsScoped] attribute to a class will mean its ServiceLifetime in the DI will be set to Scoped. Added by Fedor Zhekov (GitHub @ZFi88).

Version 2.1.0 update: Added ability ignore an interface, plus added ISerializable interface to list of ignored interfaces and outputs results so that you can check it is registering the correct things.

I have written a simple version of AutoFac's RegisterAssemblyTypes method that works directly with Microsoft's DI provider. Here are an example of me using this with ASP.NET Core.

Example 1 - scan the calling assembly

public void ConfigureServices(IServiceCollection services)
{
   //... other configure code removed

   services.RegisterAssemblyPublicNonGenericClasses()
     .Where(c => c.Name.EndsWith("Service"))  //optional
     .IgnoreThisInterface<IMyInterface>()     //optional
     .AsPublicImplementedInterfaces();

Example 2 - scanning multiple assemblies

public void ConfigureServices(IServiceCollection services)
{
   //... other configure code removed

   var assembliesToScan = new [] 
   {
        Assembly.GetExecutingAssembly(),
        Assembly.GetAssembly(typeof(MyServiceInAssembly1)),
        Assembly.GetAssembly(typeof(MyServiceInAssembly2))
   };   

   services.RegisterAssemblyPublicNonGenericClasses(assembliesToScan)
     .Where(c => c.Name.EndsWith("Service"))  //optional
     .IgnoreThisInterface<IMyInterface>()     //optional
     .AsPublicImplementedInterfaces(); 

Licence: MIT.

See this article for a bigger coverage of Microsoft DI and the use of this library in real applications.

Why have I written this extension

There are two reasons:

  1. I really hate having to hand-code each registering of the services - this extension method scans assembles and finds/registers classes with interfaces for you.
  2. I used to use AutoFac's assembly scanning feature, but I then saw a tweet by @davidfowl about Dependency Injection container benchmarks which showed the Microsoft's DI provider was much faster than AutoFac. I therefore implemented a similar (but not exactly the same) feature for the Microsoft.Extensions.DependencyInjection library.

Detailed information

There are five parts:

  1. RegisterAssemblyPublicNonGenericClasses, which finds all the public classes that :
    • Aren't abstract
    • Aren't a generic type, e.g. MyClass<AnotherClass>
    • Isn't nested. e.g. It won't look at classes defined inside other classes
  2. An Where extension method, which allows you to filter the classes to be considered.
  3. An IgnoreThisInterface<IMyInterface> extension method that allows you to add an interface to be ignored. This allows you to stop a class being registered
  4. The AsPublicImplementedInterfaces method which finds ant interfaces on a class and registers those interfaces as pointing to the class. It also returns a list of results that allows you check what classes have been registered with the DI provider.
  5. Various attributes that you can add to your classes to tell NetCore.AutoRegisterDi what to do: i) Set the ServiceLifetime of your class, e.g. [RegisterAsSingleton] to apply a Singleton lifetime to your class. ii) A [DoNotAutoRegister] attribute to stop library your class from being registered with the DI.

The following sections describes each part in detail.

1. The RegisterAssemblyPublicNonGenericClasses method

The RegisterAssemblyPublicNonGenericClasses method will find all the classes in

  1. If no assemblies are provided then it scans the assembly that called this method.
  2. You can provide one or more assemblies to be scanned. The easiest way to reference an assembly is to use something like this Assembly.GetAssembly(typeof(MyService)), which gets the assembly that MyService was defined in.

I only consider classes which match ALL of the criteria below:

  • Public access
  • Not nested, e.g. It won't look at classes defined inside other classes
  • Not Generic, e.g. MyClass<T>
  • Not Abstract

2. The Where method

Pretty straightforward - you are provided with the Type of each class and you can filter by any of the Type properties etc. This allows you to do things like only registering certain classes, e.g Where(c => c.Name.EndsWith("Service"))

NOTES:

  • Useful also if you want to register some classes with a different lifetime scope: See section 4.
  • You can use multiple Where methods. They have an && effect, e.g. the following code would register all the classes other than Class1 and Class2:
service.RegisterAssemblyPublicNonGenericClasses()
    .Where(c => c.Name != "Class1"))
    .Where(c => c.Name != "Class2"))
    .AsPublicImplementedInterfaces();

3. The IgnoreThisInterface<IMyInterface> method

There are some interfaces that you don't want your classes to be registered, for instance IDisposable and ISerializable and these are already registered in NetCore.AutoRegisterDi. This means that no class will be registered against these two interfaces.

You can add extra interfaces to the interface ignore list using the IgnoreThisInterface<IMyInterface>, e.g. the following code would add the two interfaces IMyInterface1 and IMyInterface2 to the interface ignore list.

service.RegisterAssemblyPublicNonGenericClasses()
    .IgnoreThisInterface<IMyInterface1>()
    .IgnoreThisInterface<IMyInterface2>()
    .AsPublicImplementedInterfaces();

4. The AsPublicImplementedInterfaces method

The AsPublicImplementedInterfaces method finds any public, non-nested interfaces (apart from the interfaces in the interface ignore list) that each class implements and registers each interface, known as service type, against the class, known as the implementation type. This means if you use an interface in a constructor (or other DI-enabled places) then the Microsoft DI resolver will provide an instance of the class that interface was linked to.

See Microsoft DI Docs for more on this.*

4a. Debugging what classes/interfaces have been registered

The AsPublicImplementedInterfaces method returns a list of AutoRegisteredResult classes, which shows what classes have been registered with the DI provider. By catching this result you can quickly see what the NetCore.AutoRegisterDi library has registered.

The following code would capture the list of results

var results = service.RegisterAssemblyPublicNonGenericClasses()
     .IgnoreThisInterface<IMyInterface>()
     .AsPublicImplementedInterfaces();

If you hover of the results list it will show a list similar to the one below, but with you own classes/interfaces.

The interface IDisposable is ignored
The interface ISerializable is ignored
The interface IMyInterface is ignored
LocalScopeService : ILocalService (Scoped)
LocalService : ILocalService (Transient)
LocalService : IAnotherInterface (Transient)
4b. Changing the default ServiceLifetime

The default lifetime of registered class is ServiceLifetime.Transient, there are two ways to change this.

  • Add a NetCore.AutoRegisterDi lifetime attribute to your class (see section 5).
  • You can provide a ServiceLifetime to the AsPublicImplementedInterfaces method, e.g. AsPublicImplementedInterfaces(ServiceLifetime.Scoped), which will change the default lifetime to the parameter value you provide.

See this useful article on what lifetime (and other terms) means.

5. The attributes

Fedor Zhekov, (GitHub @ZFi88) added attributes to allow you to define the ServiceLifetime of your class, and also exclude your class from being registered with the DI.

Here are the attributes that sets the ServiceLifetime to be used when NetCore.AutoRegisterDi registers your class with the DI.

  1. [RegisterAsSingleton] - Singleton lifetime.
  2. [RegisterAsTransient] - Transient lifetime.
  3. [RegisterAsScoped] - Scoped lifetime.

The last attribute is [DoNotAutoRegister], which stops NetCore.AutoRegisterDi registered that class with the DI.

More Repositories

1

AuthPermissions.AspNetCore

This library provides extra authorization and multi-tenant features to an ASP.NET Core application.
C#
774
star
2

EfCore.GenericServices

A library to help you quickly code CRUD accesses for a web/mobile/desktop application using EF Core.
C#
598
star
3

EfCoreinAction-SecondEdition

Supporting repo to go with book "Entity Framework Core in Action", second edition
C#
397
star
4

EfCore.TestSupport

Tools for helping in unit testing applications that use Entity Framework Core
C#
353
star
5

EfCoreInAction

Supporting code to go with the book "Entity Framework Core in Action"
340
star
6

PermissionAccessControl2

Version 2 of example application to go with articles on feature and data authorization
C#
276
star
7

GenericServices

GenericServices helps with building a service/application layer in a .NET based application using EF6.x
C#
245
star
8

PermissionAccessControl

Example code for Authorization articles
C#
224
star
9

EfCore.GenericBizRunner

Library to run business logic when using Entity Framework Core for database accesses
C#
216
star
10

AspNetReactSamples

Template/Sample ASP.NET projects to develop/build/test React.js apps
JavaScript
174
star
11

EfCore.SoftDeleteServices

Services to provide simple soft delete and cascade soft delete in EF Core
C#
114
star
12

EfCore.SchemaCompare

Library to compare EF Core's Model of the database against a database's schema.
C#
106
star
13

Net.DistributedFileStoreCache

NET distributed cache using a json file as the shared resourse with very fast Get
C#
96
star
14

SampleMvcWebApp

A Sample MVC5 web application showing the use of GenericServices for CRUD operations
C#
75
star
15

EfCore.GenericEventRunner

A library to allow developer use events to update their database via Entity Framework Core (EF Core)
C#
67
star
16

EfCoreSqlAndCosmos

Example CQRS application using Cosmos DB with EF Core
C#
66
star
17

BookApp.All

Example of applying an modular monolith approach to building apps. This version contains the whole app in one solution
C#
50
star
18

EfCore.GenericServices.AspNetCore

Converts EFCore.GenericServices and EfCore.GenericBizRunner statuses to ASP.NET Core formats
C#
49
star
19

EfSchemaCompare

EfSchemaCompare.EF6 allows you to compare Entity Framework's database modal with an actual SQL database.
C#
44
star
20

RunStartupMethodsSequentially

A .NET library that runs methods within a locked state on startup. This is useful if you want to migrate or seed a database on an web application that has multiple instances.
C#
32
star
21

EfCore.SoftDeleteServices-Old

Services to provide simple soft delete and cascade soft delete in EF Core
C#
29
star
22

GenericServices.StatusGeneric

Implements the "return a status" pattern - useful for code that can return errors
C#
28
star
23

SampleMvcWebAppComplex

A more complex MVC application showing the use of GenericServices with the AdventureWorksLT2012 database.
C#
26
star
24

Net.LocalizeMessagesAndErrors

This library provides extra code to make it easier to support in different languages in your .NET application
C#
18
star
25

MvcUsingBower

Applying Visual Studio's Bower/Grunt tools to a ASP.NET MVC application. See
JavaScript
16
star
26

PermissionsOnlyApp

C#
15
star
27

DDDExampleCode

Example code to go with my talk and article on DDD
C#
13
star
28

MultiProgPackTool

https://www.thereformedprogrammer.net/evolving-modular-monoliths-2-breaking-up-your-app-into-multiple-solutions/#how-to-create-a-nuget-packages
C#
9
star
29

SimpleMessageBroker

C#
5
star
30

Ef6BookApp

C#
4
star
31

AspNetCore.MultipleHostedService

C#
3
star
32

AuthP.CustomDatabaseExamples

C#
2
star
33

BookApp.Books

Part of the evolving Modular Monalith
C#
2
star
34

TryAspNetCoreMigrate

C#
2
star
35

BookApp.Main

C#
2
star
36

TestSupportSchema

C#
1
star