Skip to content

Commit

Permalink
Merge pull request #23 from futurum-dev/feature/keyed-service
Browse files Browse the repository at this point in the history
Adding 'Keyed' service registration
  • Loading branch information
futurum-dev authored Dec 21, 2023
2 parents 313efb7 + 9bb50e4 commit 03c37da
Show file tree
Hide file tree
Showing 70 changed files with 2,566 additions and 113 deletions.
173 changes: 173 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ A dotnet library that extends Microsoft.Extensions.DependencyInjection by adding

- [x] [Easy setup](#easy-setup)
- [x] Autodiscovery of DependencyInjection registrations, based on [attributes](#attribute-based-registration) and Source Generators
- [x] Support for *keyed* registrations
- [x] Autodiscovery of DependencyInjection modules, based on [attributes](#attribute-based-module) and Source Generators
- [x] Autodiscovery of DependencyInjection startables, based on [attributes](#attribute-based-startable) and Source Generators
- [x] [Roslyn Analysers](#roslyn-analysers) to help build your registrations, modules and startables, using best practices
Expand Down Expand Up @@ -36,11 +37,17 @@ You can register services using attributes.

The attributes have been created is a discoverable way. They take the following form:
- [RegisterAs{Lifetime}](#registeraslifetime-attribute)
- [RegisterAsKeyed{Lifetime}](#registeraskeyedlifetime-attribute)
- [RegisterAs{Lifetime}.AsSelf](#registeraslifetimeasself-attribute)
- [RegisterAs{Lifetime}.AsKeyedSelf](#registeraslifetimeaskeyedself-attribute)
- [RegisterAs{Lifetime}.As{ServiceType}](#registeraslifetimeasservicetype-attribute)
- [RegisterAs{Lifetime}.AsKeyed{ServiceType}](#registeraslifetimeaskeyedservicetype-attribute)
- [RegisterAs{Lifetime}.AsImplementedInterfaces](#registeraslifetimeasimplementedinterfaces-attribute)
- [RegisterAs{Lifetime}.AsKeyedImplementedInterfaces](#registeraslifetimeaskeyedimplementedinterfaces-attribute)
- [RegisterAs{Lifetime}.AsImplementedInterfacesAndSelf](#registeraslifetimeasimplementedinterfacesandself-attribute)
- [RegisterAs{Lifetime}.AsKeyedImplementedInterfacesAndSelf](#registeraslifetimeaskeyedimplementedinterfacesandself-attribute)
- [RegisterAs{Lifetime}.AsOpenGeneric](#registeraslifetimeasopengeneric-attribute)
- [RegisterAs{Lifetime}.AsKeyedOpenGeneric](#registeraslifetimeaskeyedopengeneric-attribute)

There are 3 lifetimes available:
- Singleton
Expand Down Expand Up @@ -78,6 +85,35 @@ public class Service : IService
}
```

### RegisterAsKeyed{Lifetime} attribute
This will register the class against the 1 interface the class implements, for the specified lifetime, with the *service key*.

**NOTE** - There is a Roslyn Analyser that will warn you if you use this attribute and the class does not implement exactly 1 interface.

e.g. This will register *Service* against *IService*, with a *Singleton* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsKeyedSingleton("service-key")]
public class Service : IService
{
}
```

e.g. This will register *Service* against *IService*, with a *Scoped* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsKeyedScoped("service-key")]
public class Service : IService
{
}
```

e.g. This will register *Service* against *IService*, with a *Transient* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsKeyedTransient("service-key")]
public class Service : IService
{
}
```

### RegisterAs{Lifetime}.AsSelf attribute
This will register the class against itself, for the specified lifetime.

Expand Down Expand Up @@ -105,6 +141,33 @@ public class Service
}
```

### RegisterAs{Lifetime}.AsKeyedSelf attribute
This will register the class against itself, for the specified lifetime, for the specified lifetime, with the *service key*.

e.g. This will register *Service* against *Service*, with a *Singleton* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsSingleton.AsKeyedSelf("service-key")]
public class Service
{
}
```

e.g. This will register *Service* against *Service*, with a *Scoped* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsScoped.AsKeyedSelf("service-key")]
public class Service
{
}
```

e.g. This will register *Service* against *Service*, with a *Transient* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsTransient.AsKeyedSelf("service-key")]
public class Service
{
}
```

### RegisterAs{Lifetime}.As{ServiceType} attribute
This will register the class against the specified interface, for the specified lifetime.

Expand Down Expand Up @@ -134,6 +197,35 @@ public class Service : IService1, IService2
}
```

### RegisterAs{Lifetime}.AsKeyed{ServiceType} attribute
This will register the class against the specified interface, for the specified lifetime, with the *service key*.

**NOTE** - There is a Roslyn Analyser that will warn you if you use the class does not implement the specified interface.

e.g. This will register *Service* against *IService1*, with a *Singleton* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsSingleton.AsKeyed<IService2>("service-key")]
public class Service : IService1, IService2
{
}
```

e.g. This will register *Service* against *IService1*, with a *Scoped* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsScoped.AsKeyed<IService2>("service-key")]
public class Service : IService1, IService2
{
}
```

e.g. This will register *Service* against *IService1*, with a *Transient* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsTransient.AsKeyed<IService2>("service-key")]
public class Service : IService1, IService2
{
}
```

### RegisterAs{Lifetime}.AsImplementedInterfaces attribute
This will register the class against all the interfaces it implements directly, for the specified lifetime.

Expand Down Expand Up @@ -161,6 +253,33 @@ public class Service : IService1, IService2
}
```

### RegisterAs{Lifetime}.AsKeyedImplementedInterfaces attribute
This will register the class against all the interfaces it implements directly, for the specified lifetime, with the *service key*.

e.g. This will register *Service* against *IService1* and *IService2*, with a *Singleton* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsSingleton.AsKeyedImplementedInterfaces("service-key")]
public class Service : IService1, IService2
{
}
```

e.g. This will register *Service* against *IService1* and *IService2*, with a *Scoped* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsScoped.AsKeyedImplementedInterfaces("service-key")]
public class Service : IService1, IService2
{
}
```

e.g. This will register *Service* against *IService1* and *IService2*, with a *Transient* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsTransient.AsKeyedImplementedInterfaces("service-key")]
public class Service : IService1, IService2
{
}
```

### RegisterAs{Lifetime}.AsImplementedInterfacesAndSelf attribute
This will register the class against all the interfaces it implements directly and itself, for the specified lifetime.

Expand Down Expand Up @@ -188,6 +307,33 @@ public class Service : IService1, IService2
}
```

### RegisterAs{Lifetime}.AsKeyedImplementedInterfacesAndSelf attribute
This will register the class against all the interfaces it implements directly and itself, for the specified lifetime, with the *service key*.

e.g. This will register *Service* against *Service*, *IService1* and *IService2*, with a *Singleton* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsSingleton.AsKeyedImplementedInterfacesAndSelf("service-key")]
public class Service : IService1, IService2
{
}
```

e.g. This will register *Service* against *Service*, *IService1* and *IService2*, with a *Scoped* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsScoped.AsKeyedImplementedInterfacesAndSelf("service-key")]
public class Service : IService1, IService2
{
}
```

e.g. This will register *Service* against *Service*, *IService1* and *IService2*, with a *Transient* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsTransient.AsKeyedImplementedInterfacesAndSelf("service-key")]
public class Service : IService1, IService2
{
}
```

### RegisterAs{Lifetime}.AsOpenGeneric attribute
This will register the an open generic class against an open generic interface, for the specified lifetime.

Expand Down Expand Up @@ -215,6 +361,33 @@ public class Service<T> : IService<T>
}
```

### RegisterAs{Lifetime}.AsKeyedOpenGeneric attribute
This will register the an open generic class against an open generic interface, for the specified lifetime, with the *service key*.

e.g. This will register *Service&lt;T&gt;* against *IService&lt;T&gt;*, with a *Singleton* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsSingleton.AsKeyedOpenGeneric("service-key", ImplementationType = typeof(Service<>), ServiceType = typeof(IService<>))]
public class Service<T> : IService<T>
{
}
```

e.g. This will register *Service&lt;T&gt;* against *IService&lt;T&gt;*, with a *Scoped* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsScoped.AsKeyedOpenGeneric("service-key", ImplementationType = typeof(Service<>), ServiceType = typeof(IService<>))]
public class Service<T> : IService<T>
{
}
```

e.g. This will register *Service&lt;T&gt;* against *IService&lt;T&gt;*, with a *Transient* lifetime, with a *"service-key"* service key.
```csharp
[RegisterAsTransient.AsKeyedOpenGeneric("service-key", ImplementationType = typeof(Service<>), ServiceType = typeof(IService<>))]
public class Service<T> : IService<T>
{
}
```

### DuplicateRegistrationStrategy
**All** registration attributes allow you to specify how to handle duplicate registrations.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Futurum.Microsoft.Extensions.DependencyInjection.Generator.Sample;

public interface IService1
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Futurum.Microsoft.Extensions.DependencyInjection.Generator.Sample;

public interface IService2
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Futurum.Microsoft.Extensions.DependencyInjection.Generator.Sample;

public interface IService3
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Futurum.Microsoft.Extensions.DependencyInjection.Generator.Sample;

public interface IService_OpenGeneric<T>
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ public interface IModuleService

public class ModuleService : IModuleService
{
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
namespace Futurum.Microsoft.Extensions.DependencyInjection.Generator.Sample;

public interface IService1
{
}

public interface IService2
{
}

public interface IService3
{
}

public interface IService4
[RegisterAsTransient]
public class TransientService : IService1
{
}

Expand All @@ -36,6 +25,11 @@ public class TransientService_AsImplementedInterfacesAndSelf : IService1
{
}

[RegisterAsScoped]
public class ScopedService : IService2
{
}

[RegisterAsScoped.AsSelf]
public class ScopedService_AsSelf : IService2
{
Expand All @@ -56,6 +50,11 @@ public class ScopedService_AsImplementedInterfacesAndSelf : IService2
{
}

[RegisterAsSingleton]
public class SingletonService : IService3
{
}

[RegisterAsSingleton.AsSelf]
public class SingletonService_AsSelf : IService3
{
Expand Down Expand Up @@ -96,10 +95,6 @@ public class Service_AsImplementedInterfaces : IService1, IService2
{
}

public interface IService_OpenGeneric<T>
{
}

[RegisterAsTransient.AsOpenGeneric(ImplementationType = typeof(TransientService_AsOpenGeneric<>), ServiceType = typeof(IService_OpenGeneric<>))]
public class TransientService_AsOpenGeneric<T> : IService_OpenGeneric<T>
{
Expand All @@ -113,4 +108,4 @@ public class ScopedService_AsOpenGeneric<T> : IService_OpenGeneric<T>
[RegisterAsSingleton.AsOpenGeneric(ImplementationType = typeof(SingletonService_AsOpenGeneric<>), ServiceType = typeof(IService_OpenGeneric<>))]
public class SingletonService_AsOpenGeneric<T> : IService_OpenGeneric<T>
{
}
}
Loading

0 comments on commit 03c37da

Please sign in to comment.