DBaker.DepRegAttributes 6.0.0

Suggested Alternatives

DBaker.DepRegAttributes 8.0.0

Additional Details

Upgrade to 8.0.0 if you can install Microsoft.Extensions.DependencyInjection.Abstractions 8.0.0 (Note: Microsoft.Extensions.DependencyInjection.Abstractions 8.0.0 targets netstandard 2.0).

Otherwise upgrade to 3.1.0.

There is a newer version of this package available.
See the version list below for details.
dotnet add package DBaker.DepRegAttributes --version 6.0.0                
NuGet\Install-Package DBaker.DepRegAttributes -Version 6.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="DBaker.DepRegAttributes" Version="6.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DBaker.DepRegAttributes --version 6.0.0                
#r "nuget: DBaker.DepRegAttributes, 6.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 DBaker.DepRegAttributes as a Cake Addin
#addin nuget:?package=DBaker.DepRegAttributes&version=6.0.0

// Install DBaker.DepRegAttributes as a Cake Tool
#tool nuget:?package=DBaker.DepRegAttributes&version=6.0.0                

Dependency Registration Attributes

Register dependencies with attributes and never touch your Program.cs file again!

Example usage in .NET Standard 2.0:

[RegisterTransient]
public class TransientRegisteredAsSelf
{
    //This will be registered as TransientRegisteredAsSelf
    ...
}

[RegisterTransient]
public class TransientRegisteredAsInterface : ITransientRegisteredAsInterface
{
    //This will be registered as ITransientRegisteredAsInterface
    //This only automatically happens if the interface and class name match
    //Note: providing any parameters will override this behavior
    ...
}

[RegisterTransient(typeof(IInterface))] //.NET Standard
[RegisterTransient<IInterface>] //In .NET 7 or later
public class TransientRegisteredWithInterface: IInterface
{
    //This will be registered as IInterface
    ...
}

[RegisterTransient(typeof(IInterface))] //.NET Standard
[RegisterTransient<IInterface>] //In .NET 7 or later
public class TransientRegisteredWithInterface: ITransientRegisteredAsInterface, IInterface
{
    //This will be registered only as IInterface
    //Providing parameters overrides the automatic registration by interfaces with the same name
    ...
}

[RegisterTransient(typeof(IInterface1), typeof(IInterface2))] //.NET Standard
[RegisterTransient<IInterface1, IInterface2>] //In .NET 7 or later
public class TransientRegisteredWithMultipleInterface: IInterface1, IInterface2
{
    //This will be registered as IInterface1 and IInterface2
    ...
}

[RegisterSingleton(typeof(IInterface1), typeof(IInterface2))] //.NET Standard
[RegisterTransient<IInterface1, IInterface2>] //In .NET 7 or later
public class SingletonRegisteredWithMultipleInterface: IInterface1, IInterface2
{
    //This will be registered as IInterface1 and IInterface2
    //Requesting either interface from the service provider will give you the exact same object
    ...
}

You can register Transient, Scoped, and Singletons:

[RegisterTransient]
...

[RegisterScoped]
...

[RegisterSingleton]
...

In order for the attributes to work you will need to create an extension in the project you are using the attributes:

public static class ServiceCollectionExtentions
{
    public static IServiceCollection AddExampleLibraryRegistration(this IServiceCollection services)
    {
        return services.RegisterDependenciesByAttribute();
    }
}

You can use tagging to filter the servicees you register. If you add no tag, your service will be registered all the time.

[RegisterTransient("tag1", "tag2")]
public class TagExample1
{
    ...
}

[RegisterTransient(new[] { "tag2", "tag3" }, typeof(IInterface1), typeof(IInterface2))]
public class TagExample2 : IInterface1, IInterface2
{
    ...
}

//register dependencies based on tag
public static class ServiceCollectionExtentions
{
    public static IServiceCollection AddByTag(this IServiceCollection services)
    {
        //This will get TagExample1
        return services.RegisterDependenciesByAttribute("tag1");
    }

    public static IServiceCollection AddByTag2(this IServiceCollection services)
    {
        //This will get TagExample1 and TagExample2
        return services.RegisterDependenciesByAttribute("tag2");
    }

    public static IServiceCollection AddByTag3(this IServiceCollection services)
    {
        //This will get TagExample2
        return services.RegisterDependenciesByAttribute("tag3");
    }

    public static IServiceCollection AddAll(this IServiceCollection services)
    {
        //This will get TagExample1 and TagExample2
        return services.RegisterDependenciesByAttribute();
    }
}

Advanced Scenarios

Registering grouped Singleton/Scoped

This will allow you to have two singletons in the service provider based on interfaces. For example, requesting ISingletonGroup1 or ISingletonGroup1_2 will give you the same object. Requesting ISingletonGroup2 or ISingletonGroup2_2 will give you the same object, but it will be different from the ISingletonGroup1 object

[RegisterSingleton<ISingletonGroup1, ISingletonGroup1_2>]
[RegisterSingleton<ISingletonGroup2, ISingletonGroup2_2>]
public class SingletonClassGroupedByIterfaces: 
    ISingletonGroup1, 
    ISingletonGroup1_2, 
    ISingletonGroup2, 
    ISingletonGroup2_2
{
}

[TestMethod]
public void GetSingletonGroupsTest()
{
    //Arrange
    var sut = CreateSut();

    //Act
    var singletonGroup1 = sut.GetRequiredService<ISingletonGroup1>();
    var singletonGroup1_2 = sut.GetRequiredService<ISingletonGroup1_2>();
    var singletonGroup2 = sut.GetRequiredService<ISingletonGroup2>();
    var singletonGroup2_2 = sut.GetRequiredService<ISingletonGroup2_2>();

    //Assert
    Assert.IsNotNull(singletonGroup1);
    Assert.IsNotNull(singletonGroup1_2);
    Assert.AreEqual(singletonGroup1, singletonGroup1_2);

    Assert.IsNotNull(singletonGroup2);
    Assert.IsNotNull(singletonGroup2_2);
    Assert.AreEqual(singletonGroup2, singletonGroup2_2);

    Assert.AreNotEqual(singletonGroup1, singletonGroup2);
    Assert.AreNotEqual(singletonGroup1, singletonGroup2_2);
    Assert.AreNotEqual(singletonGroup1_2, singletonGroup2);
    Assert.AreNotEqual(singletonGroup1_2, singletonGroup2_2);
}

Implementing a factory

This is a very limited concept, but might be useful. It's possible new verison of C# will make this significantly more useful. For now, you can assign a value to the base ObjectFactory property. It looks like this:

protected virtual Func<IServiceProvider, Type, object> ObjectFactory { get; set; }

Again this is extremely limited, but I added it because I wanted to have an easy way to bind objects to configuration in ASP.NET Core. Here is an example:

[AttributeUsage(AttributeTargets.Class)]
private class RegisterConfigAttribute : RegisterSingletonAttribute
{
    public RegisterConfigAttribute(string configKey)
    {
        ObjectFactory = (sp, t) =>
        {
            var config = Activator.CreateInstance(t);
            sp.GetRequiredService<IConfiguration>().Bind(configKey, config);
            return config;
        };
    }
}

This will have the effect of registering a singleton object in the service provider. Additionally it will automatically bind the object to a section in your appsettings.json file, determined by the configKey.

Then we can use it on a class like this:

public interface IConfigClass
{
    string Example { get; }
}

[RegisterConfig("Config")]
public class ConfigClass : IConfigClass
{
    public string Example { get; set; } = string.Empty;
}

If the following is in your appsettings.json file, the "Config" section will be automatically be mapped to the IConfigClass.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  },
  "AllowedHosts": "*",
  "Config": {
    "Example": "A Value"
  }
}

You can look at examples of usage in the DepRegAttributes.Example and DepRegAttributes.ExampleLibrary projects.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  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 was computed. 
.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.