Skip to content

Commit 54f319d

Browse files
committed
Added result for DI registering + updated docs
1 parent 434da4b commit 54f319d

File tree

5 files changed

+107
-34
lines changed

5 files changed

+107
-34
lines changed

NetCore.AutoRegisterDi/NetCore.AutoRegisterDi.csproj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414
<RepositoryType>GitHub</RepositoryType>
1515
<PackageTags>NetCore DependencyInjection di</PackageTags>
1616
<Authors>Jon P Smith</Authors>
17-
<Copyright>Copyright (c) 2018 Selective Analytics Ltd.</Copyright>
17+
<Copyright>Copyright (c) 2020 Selective Analytics Ltd.</Copyright>
1818
<Company>Selective Analytics</Company>
1919
<Description>Extension method to find/register classes in an assembly into Microsoft.Extensions.DependencyInjection</Description>
2020
<PackageReleaseNotes>
21-
- New feature: IgnoreThisInterface method allows you to state that the given interface will not be registered against a class
22-
- Improvement: Adds ISerializable interface base list interfaces to ignore (IDisposable is already in base ignore list)
23-
- Improvement: You can use muliple have Where methods to filter
24-
- Improvement: Returns a list of the classes that were registered with the DI provider (and what interfaces were ignored)
21+
- New feature: IgnoreThisInterface method adds a interface to its interface ignore list.
22+
- Improvement: Added ISerializable interface to the default interface ignore list (IDisposable is already in base ignore list)
23+
- Improvement: You can use muliple have Where methods to filter out classes
24+
- Improvement: Returns a list of the classes/interfaces registered with the DI provider (useful for debugging)
2525
</PackageReleaseNotes>
2626
<PackageIconUrl>https://raw.githubusercontent.com/JonPSmith/NetCore.AutoRegisterDi/master/AutoRegisterDiIcon128.png</PackageIconUrl>
2727
</PropertyGroup>

READMe.md

Lines changed: 79 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,24 @@ This [NuGet library](https://www.nuget.org/packages/NetCore.AutoRegisterDi/) con
44

55
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.
66

7-
**Version 2 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)*.
7+
**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)*.
88

9-
#### Example 1 - scan the calling assembly
9+
**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.
10+
11+
## Example 1 - scan the calling assembly
1012

1113
```c#
1214
public void ConfigureServices(IServiceCollection services)
1315
{
1416
//... other configure code removed
1517
1618
service.RegisterAssemblyPublicNonGenericClasses()
17-
.Where(c => c.Name.EndsWith("Service"))
19+
.Where(c => c.Name.EndsWith("Service")) //optional
20+
.IgnoreThisInterface<IMyInterface>() //optional
1821
.AsPublicImplementedInterfaces();
1922
```
2023

21-
22-
#### Example 2 - scaning multiple assemblies
24+
## Example 2 - scanning multiple assemblies
2325

2426
```c#
2527
public void ConfigureServices(IServiceCollection services)
@@ -34,17 +36,17 @@ public void ConfigureServices(IServiceCollection services)
3436
};
3537

3638
service.RegisterAssemblyPublicNonGenericClasses(assembliesToScan)
37-
.Where(c => c.Name.EndsWith("Service"))
39+
.Where(c => c.Name.EndsWith("Service")) //optional
40+
.IgnoreThisInterface<IMyInterface>() //optional
3841
.AsPublicImplementedInterfaces();
3942
```
4043

41-
4244
Licence: MIT.
4345

4446
**See [this article](https://www.thereformedprogrammer.net/asp-net-core-fast-and-automatic-dependency-injection-setup/)
4547
for a bigger coverage of Microsoft DI and the use of this library in real applications.**
4648

47-
## Why have I written this extension?
49+
## Why have I written this extension
4850

4951
There are two reasons:
5052

@@ -57,66 +59,114 @@ which showed the Microsoft's DI provider was much faster than AutoFac.
5759
I therefore implemented a similar (but not exactly the same) feature for the
5860
Microsoft.Extensions.DependencyInjection library.
5961

62+
## Detailed information
6063

61-
### Detailed information
62-
63-
There are four parts:
64+
There are five parts:
6465
1. `RegisterAssemblyPublicNonGenericClasses`, which finds all the public classes that :
6566
- Aren't abstract
6667
- Aren't a generic type, e.g. MyClass\<AnotherClass\>
6768
- Isn't nested. e.g. It won't look at classes defined inside other classes
68-
2. An options `Where` method, which allows you to filter the classes to be considered.
69-
3. The `AsPublicImplementedInterfaces` method which finds ant interfaces on a class and registers those interfaces as pointing to the class.
70-
4. Various attributes that you can add to your classes to tell `NetCore.AutoRegisterDi` what to do:
69+
2. An `Where` extension method, which allows you to filter the classes to be considered.
70+
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
71+
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.
72+
5. Various attributes that you can add to your classes to tell `NetCore.AutoRegisterDi` what to do:
7173
i) Set the `ServiceLifetime` of your class, e.g. `[RegisterAsSingleton]` to apply a `Singleton` lifetime to your class.
7274
ii) A `[DoNotAutoRegister]` attribute to stop library your class from being registered with the DI.
7375

76+
The following sections describes each part in detail.
7477

75-
#### 1. The `RegisterAssemblyPublicNonGenericClasses` method
78+
### 1. The `RegisterAssemblyPublicNonGenericClasses` method
7679

7780
The `RegisterAssemblyPublicNonGenericClasses` method will find all the classes in
7881

7982
1. If no assemblies are provided then it scans the assembly that called this method.
8083
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.
8184

82-
I only consider classes which match ALL of the critera below:
85+
I only consider classes which match ALL of the criteria below:
8386

8487
- Public access
8588
- Not nested, e.g. It won't look at classes defined inside other classes
8689
- Not Generic, e.g. MyClass\<T\>
8790
- Not Abstract
8891

89-
90-
#### 2. The `Where` method
92+
### 2. The `Where` method
9193

9294
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"))`
9395

94-
*NOTE: Useful also if you want to register some classes with a different timetime scope - See next section.*
96+
*NOTES:*
97+
98+
- Useful also if you want to register some classes with a different lifetime scope: See section 4.
99+
- 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`:
100+
101+
```c#
102+
service.RegisterAssemblyPublicNonGenericClasses()
103+
.Where(c => c.Name != "Class1"))
104+
.Where(c => c.Name != "Class2"))
105+
.AsPublicImplementedInterfaces();
106+
```
107+
108+
### 3. The `IgnoreThisInterface<IMyInterface>` method
109+
110+
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.
111+
112+
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.
113+
114+
```c#
115+
service.RegisterAssemblyPublicNonGenericClasses()
116+
.IgnoreThisInterface<IMyInterface1>()
117+
.IgnoreThisInterface<IMyInterface2>()
118+
.AsPublicImplementedInterfaces();
119+
```
95120

96-
#### 3. The `AsPublicImplementedInterfaces` method
121+
### 4. The `AsPublicImplementedInterfaces` method
97122

98123
The `AsPublicImplementedInterfaces` method finds any public, non-nested interfaces
99-
(apart from `IDisposable`) that each class implements and registers each
100-
interface, known as *service type*, against the class, known as the *implementation type*.
101-
This means if you use an interface in a constructor (or other DI-enabled places)
102-
then the Microsoft DI resolver will provide an instance of the class that interface
124+
(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
103125
was linked to.
126+
104127
*See [Microsoft DI Docs](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1) for more on this*.*
105128
106-
By default it will register the classes as having a lifetime of `ServiceLifetime.Transient`,
107-
but there is a parameter that allows you to override that.
129+
#### 4a. Debugging what classes/interfaces have been registered
130+
131+
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.
132+
133+
The following code would capture the list of results
134+
135+
```c#
136+
var results = service.RegisterAssemblyPublicNonGenericClasses()
137+
.IgnoreThisInterface<IMyInterface>()
138+
.AsPublicImplementedInterfaces();
139+
```
140+
141+
If you hover of the `results` list it will show a list similar to the one below, but with you own classes/interfaces.
142+
143+
```text
144+
The interface IDisposable is ignored
145+
The interface ISerializable is ignored
146+
The interface IMyInterface is ignored
147+
LocalScopeService : ILocalService (Scoped)
148+
LocalService : ILocalService (Transient)
149+
LocalService : IAnotherInterface (Transient)
150+
```
151+
152+
##### 4b. Changing the default ServiceLifetime
153+
154+
The default lifetime of registered class is `ServiceLifetime.Transient`, there are two ways to change this.
155+
156+
- Add a NetCore.AutoRegisterDi lifetime attribute to your class (see section 5).
157+
- 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.
108158

109159
*See this [useful article](https://joonasw.net/view/aspnet-core-di-deep-dive)
110160
on what lifetime (and other terms) means.*
111161

112-
#### 4. The attributes
162+
### 5. The attributes
113163

114-
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.
164+
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.
115165

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

118168
1. `[RegisterAsSingleton]` - Singleton lifetime.
119169
2. `[RegisterAsTransient]` - Transient lifetime.
120170
3. `[RegisterAsScoped]` - Scoped lifetime.
121171

122-
The last attribute is `[DoNotAutoRegister]`, which stops `NetCore.AutoRegisterDi` registered that class with the DI.
172+
The last attribute is `[DoNotAutoRegister]`, which stops `NetCore.AutoRegisterDi` registered that class with the DI.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System;
2+
3+
namespace Test.DifferentServices
4+
{
5+
public class MyException : Exception
6+
{
7+
8+
}
9+
}

Test/TestAutoRegisterDiCallingAssembly.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ public void TestRegisterAssemblyPublicNonGenericClasses()
3131
{
3232
typeof(TestAutoRegisterDiCallingAssembly),
3333
typeof(TestAutoRegisterDiDifferentAssembly),
34+
typeof(TestAutoRegisterResult),
3435
typeof(TestTypeExtensions),
3536
typeof(ClassWithJustIDisposable),
3637
typeof(ClassWithJustISerializable),
3738
typeof(LocalScopeService), typeof(LocalService),
3839
typeof(LocalSingletonService), typeof(LocalTransientService),
40+
typeof(MyException)
3941
});
4042
}
4143

Test/TestAutoRegisterResult.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,19 @@
66
using NetCore.AutoRegisterDi;
77
using Test.DifferentServices;
88
using Xunit;
9+
using Xunit.Abstractions;
910
using Xunit.Extensions.AssertExtensions;
1011

1112
namespace Test
1213
{
1314
public class TestAutoRegisterResult
1415
{
16+
private ITestOutputHelper _output;
17+
18+
public TestAutoRegisterResult(ITestOutputHelper output)
19+
{
20+
_output = output;
21+
}
1522

1623
[Fact]
1724
public void TestAsPublicImplementedInterfacesMyService()
@@ -34,6 +41,11 @@ public void TestAsPublicImplementedInterfacesMyService()
3441
resultsAsString.ShouldContain("LocalSingletonService : ILocalService (Singleton)");
3542
resultsAsString.ShouldContain("LocalTransientService : ILocalService (Transient)");
3643
resultsAsString.ShouldContain("LocalScopeService : ILocalService (Scoped)");
44+
45+
foreach (var result in resultsAsString)
46+
{
47+
_output.WriteLine(result);
48+
}
3749
}
3850

3951
[Fact]

0 commit comments

Comments
 (0)