Injectable.NetCore.Extensions 2.0.0

dotnet add package Injectable.NetCore.Extensions --version 2.0.0
NuGet\Install-Package Injectable.NetCore.Extensions -Version 2.0.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Injectable.NetCore.Extensions" Version="2.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Injectable.NetCore.Extensions --version 2.0.0
#r "nuget: Injectable.NetCore.Extensions, 2.0.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Injectable.NetCore.Extensions as a Cake Addin
#addin nuget:?package=Injectable.NetCore.Extensions&version=2.0.0

// Install Injectable.NetCore.Extensions as a Cake Tool
#tool nuget:?package=Injectable.NetCore.Extensions&version=2.0.0

Injectable.NetCore.Extensions

Injectable Extensions enable simple, convention-based injection for .Net Core and .Net Standard services.

Injectable Extensions streamlines dependency injection in .Net Core and .Net Standard development scenarios by providing a set of extensions methods which enable convention-based injection from loaded assemblies. The extensions can be used directly from any IServiceCollection, or a broader set of injection rules can be provided via the InjectionSettings class.

Installation

From Package Manager Console:

Install-Package Injectable.NetCore.Extensions

From Cli:

dotnet add package Injectable.NetCore.Extensions

Injection Scopes

Injectable Extensions supports three forms of injection scopes provided by the InjectionMode enum:

namespace Injectable.NetCore.Extensions
{
    public enum InjectionMode
    {
        Scoped,
        Singleton,
        Transient
    }
}

InjectionSettings

This is the definition of the IInjectionSettings interface. Any implementation of this interface can be passed into the InjectByConvention method.

Property Type Default Usage
InterfacePrefix string null Prefix of interface types, defaults to "I"
InterfaceSuffixList List<string> Interface suffixs to identify injectables
InterfaceRootNamespaces List<string> Namespaces to load interfaces from
EnforceStrictNaming bool true When set to true, Injected classes must have the same name as the interface, without the leading prefix <br /><br />For Example: INameProvider will inject the NameProvider class, but not TheNameProvider, even if TheNameProvider implements INameProvider
RestrictImplementationsToInterfaceNamespaces bool false When set to true, only classes in the same root namespaces as the interface collections they implement will be injected
AllowedImplementationNamespaces List<string> <p>Defines the list of namespaces where implementation of the interfaces is allowed for injection</p><p>An empty or null list will allow implementation in any namespace unless restricted by the RestrictImplementationsToInterfaceNamespaces property</p><p>Namespaces can be provided as the partially (ends with) or fully Qualified Namespace</p><p>For Example: To inject an implementation from MyAssembly.Utilities.Dates any of the following will work<br /><br />"MyAssembly.Utilities.Dates"<br />"Utilities.Dates"<br />"Dates"</p>
InjectionMode InjectionMode InjectionMode.Scoped Specifies the injection mode from Injectable.NetCore.Extensions.InjectionMode
ForceImplementationForAllDefinitions bool true When true, thows an exception if any interface matching the convention is not implemented
Method Returns Usage
Validate() void Checks settings for minimum viable usability, throws an InvalidOperationException if validation criteria fails
Configure(bool forceImplementationForAllDefinitions = true) IInjectionRootNamespaceConfiguration Begins Fluent Configuration

Usage 1: Fluent Injection

There is a fluent method for configuring the IInjectionSettings in the package that will guide you through the completion of valid settings.

If your interface declarations are:

namespace MyNamespace.ServiceContracts {

    public interface IPersonService {}
    public interface IAddressService {}
}
namespace MyUfoNamespace {
    public interface IUfoService {}
}

By convention, your implementations are:

namespace MyOtherNamespace.Services {

    public class PersonService: IPersonService {}
    public class AddressService: IAddressService {}
    public class UfoService: IUfoService {}
}

This method of injection will look similar to this:

public void ConfigureServices(IServiceCollection services){
    
    var injectionSettings = InjectionSettings
        .WithInjectionMode(InjectionMode.Scoped)
        .WithRootNamespaces("MyNamespace", "MyUfoNamespace")
        .AllowImplementationsInAnyNamespace()
        .WithInterfacePrefix("I")
        .WithInterfaceSuffix("Service")
        .WithStrictNaming();

    services.InjectByConvention(injectionSettings);
}

This will result in All Interfaces starting with "I" and ending in "Service" residing anywhere in the InjectionClasses or InjectionClasses2 namespaces with implementations whose class names match the interface names (without the prefix). Since multiple root namespaces were specified, all the implementations will be injected.

Usage 2: Explicit Scope Injection

Explicit extension methods exist for each type of scope by providing a root namespace and suffix. So if my convention for naming your service interfaces is "I<ClassName>Service" (we default the prefix to "I", but that can also be overriden)

If your interface declarations are:

namespace MyNamespace.ServiceContracts {

    public interface IPersonService {}
    public interface IAddressService {}
    public interface IUfoService {}
}

By convention, your implementations are:

namespace MyOtherNamespace.Services {

    public class PersonService: IPersonService {}
    public class AddressService: IAddressService {}
    public class UfoService: IUfoService {}
}

Then injecting those into your services is as easy as:

public void ConfigureServices (IServiceCollection services) {

    // Transient injection
    services.InjectTransientsFrom("MyNamespace", "Services");
    // Scoped injection
    services.InjectScopedFrom("MyNamespace", "Services");
    // Singleton injection
    services.InjectSingletonsFrom("MyNamespace", "Services");
}

There are many optional parameters to the Inject extenstions that allow you to customize the behavior which all roll up into an InjectionSettings instance before being passed into the InjectByConvention method.

Reflection, Injection, and Multiple Implementations

I realize there is nothing that prevents or restricts the implementation of an interface on multiple classes. HOWEVER, there is a limitation on this imposed by the dependency injection process that does not allow multiple implementations for injected types. This will cause an error.

Change Log

Version Changes
2.0.0.0 Updated to support Net 6 and 7
1.4.0.0 Fixed a bug when using no suffix list, added xml documentation
1.3.0.1 <ul><li>Added type-based option for supplying fluent namespaces</li><li>Added Change Log to readme.md</li></ul>
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.0.0 419 11/11/2022
1.4.0 366 11/3/2022
1.3.0.1 363 9/29/2021
1.2.0.2 1,986 12/12/2020
1.2.0.1 740 5/29/2020
1.2.0 466 5/29/2020
1.1.0 478 3/20/2020
1.0.3.1 618 7/31/2019
1.0.2 593 6/8/2019
1.0.1 568 5/31/2019

Added Net 6 and Net 7 support