├── .gitignore ├── src └── Nano.DependencyInjector │ ├── ScopedAttribute.cs │ ├── SingletonAttribute.cs │ ├── TransientAttribute.cs │ ├── InjectAttribute.cs │ ├── DependencyInjectionServiceType.cs │ ├── Nano.DependencyInjector.csproj │ ├── ListExtension.cs │ ├── DependencyInjectionConfigure.cs │ └── NanoDependencyInjectorExtensions.cs ├── tests ├── Nano.APIExample │ ├── Services │ │ ├── IScopedTestService.cs │ │ ├── ISingletonTestService.cs │ │ ├── ITransientTestService.cs │ │ └── Implementations │ │ │ ├── ScopedTestService.cs │ │ │ ├── SingletonTestService.cs │ │ │ └── TransientTestService.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── Nano.APIExample.csproj │ ├── WeatherForecast.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Controllers │ │ ├── TestController.cs │ │ └── WeatherForecastController.cs │ └── Startup.cs └── Nano.DependencyInjector.Tests │ ├── Nano.DependencyInjector.Tests.csproj │ └── ListExtensionTests.cs ├── .github └── workflows │ └── main.yml ├── Nano.DependencyInjector.sln └── Readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | /packages/ 4 | riderModule.iml 5 | /_ReSharper.Caches/ 6 | .idea/ -------------------------------------------------------------------------------- /src/Nano.DependencyInjector/ScopedAttribute.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | using System; 3 | 4 | public class ScopedAttribute : Attribute 5 | { 6 | } -------------------------------------------------------------------------------- /src/Nano.DependencyInjector/SingletonAttribute.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | using System; 3 | 4 | public class SingletonAttribute : Attribute 5 | { 6 | } -------------------------------------------------------------------------------- /src/Nano.DependencyInjector/TransientAttribute.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | using System; 3 | 4 | public class TransientAttribute : Attribute 5 | { 6 | } -------------------------------------------------------------------------------- /tests/Nano.APIExample/Services/IScopedTestService.cs: -------------------------------------------------------------------------------- 1 | namespace Nano.APIExample.Services 2 | { 3 | public interface IScopedTestService 4 | { 5 | string Test(); 6 | } 7 | } -------------------------------------------------------------------------------- /tests/Nano.APIExample/Services/ISingletonTestService.cs: -------------------------------------------------------------------------------- 1 | namespace Nano.APIExample.Services 2 | { 3 | public interface ISingletonTestService 4 | { 5 | string Test(); 6 | } 7 | } -------------------------------------------------------------------------------- /tests/Nano.APIExample/Services/ITransientTestService.cs: -------------------------------------------------------------------------------- 1 | namespace Nano.APIExample.Services 2 | { 3 | public interface ITransientTestService 4 | { 5 | string Test(); 6 | } 7 | } -------------------------------------------------------------------------------- /tests/Nano.APIExample/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/Nano.APIExample/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /src/Nano.DependencyInjector/InjectAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Nano.DependencyInjector 6 | { 7 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)] 8 | public class InjectAttribute : Attribute 9 | { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/Nano.APIExample/Nano.APIExample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/Nano.APIExample/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Nano.APIExample 4 | { 5 | public class WeatherForecast 6 | { 7 | public DateTime Date { get; set; } 8 | 9 | public int TemperatureC { get; set; } 10 | 11 | public int TemperatureF => 32 + (int) (TemperatureC / 0.5556); 12 | 13 | public string Summary { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Nano.DependencyInjector/DependencyInjectionServiceType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace Nano.DependencyInjector 5 | { 6 | internal class DependencyInjectionServiceType 7 | { 8 | public Type ImplementationType { get; set; } 9 | public Type InterfaceType { get; set; } 10 | public ServiceLifetime LifeTime { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /tests/Nano.APIExample/Services/Implementations/ScopedTestService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Nano.APIExample.Services.Implementations 4 | { 5 | [Scoped] 6 | public class ScopedTestService : IScopedTestService 7 | { 8 | public ScopedTestService() 9 | { 10 | Console.WriteLine("Created scoped instance"); 11 | } 12 | 13 | public string Test() 14 | { 15 | return "Scoped"; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /tests/Nano.APIExample/Services/Implementations/SingletonTestService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Nano.APIExample.Services.Implementations 4 | { 5 | [Singleton] 6 | public class SingletonTestService : ISingletonTestService 7 | { 8 | public SingletonTestService() 9 | { 10 | Console.WriteLine("Created singleton instance"); 11 | } 12 | 13 | public string Test() 14 | { 15 | return "Singleton"; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /tests/Nano.APIExample/Services/Implementations/TransientTestService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Nano.APIExample.Services.Implementations 4 | { 5 | [Transient] 6 | public class TransientTestService : ITransientTestService 7 | { 8 | public TransientTestService() 9 | { 10 | Console.WriteLine("Created transient instance"); 11 | } 12 | 13 | public string Test() 14 | { 15 | return "Transient"; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /tests/Nano.APIExample/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.Hosting; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace Nano.APIExample 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | CreateHostBuilder(args).Build().Run(); 17 | } 18 | 19 | public static IHostBuilder CreateHostBuilder(string[] args) => 20 | Host.CreateDefaultBuilder(args) 21 | .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); 22 | } 23 | } -------------------------------------------------------------------------------- /tests/Nano.DependencyInjector.Tests/Nano.DependencyInjector.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/Nano.DependencyInjector.Tests/ListExtensionTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Xunit; 3 | 4 | namespace Nano.DependencyInjector.Tests 5 | { 6 | public class ListExtensionTests 7 | { 8 | [Fact] 9 | public void TrueFunc_Should_Get_Items_When_Statement_Is_True() 10 | { 11 | var falseHeroes = new List(); 12 | var heroes = new List() {"Conan", "Spawn", "Batman"}; 13 | heroes.If(IsBestHero) 14 | .True(t => Assert.Equal("Conan", t)) 15 | .False(f => falseHeroes.Add(f)); 16 | 17 | Assert.Equal(2, falseHeroes.Count); 18 | } 19 | 20 | private bool IsBestHero(string hero) 21 | { 22 | return hero == "Conan"; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /tests/Nano.APIExample/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:36600", 8 | "sslPort": 44349 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "weatherforecast", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "Nano.APIExample": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "weatherforecast", 24 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Nano.DependencyInjector/Nano.DependencyInjector.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.1 5 | Nano.DependencyInjector 6 | 1.0.0 7 | Baris Ceviz 8 | Nano.DependencyInjector 9 | Easy to apply dependency injection with aspect-oriented programming style 10 | Copyright @2020 Baris Ceviz 11 | https://github.com/peacecwz/nano-dependency-injector/blob/master/LICENSE 12 | https://github.com/peacecwz/nano-dependency-injector 13 | https://github.com/peacecwz/nano-dependency-injector.git 14 | git 15 | dependency-injector, dependency-injection, nano-dependency-injector 16 | true 17 | true 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/Nano.APIExample/Controllers/TestController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Nano.APIExample.Services; 3 | 4 | namespace Nano.APIExample.Controllers 5 | { 6 | [Route("v1/test")] 7 | public class TestController : Controller 8 | { 9 | private readonly ISingletonTestService _singletonTestService; 10 | private readonly IScopedTestService _scopedTestService; 11 | private readonly ITransientTestService _transientTestService; 12 | 13 | public TestController(ISingletonTestService singletonTestService, IScopedTestService scopedTestService, 14 | ITransientTestService transientTestService) 15 | { 16 | _singletonTestService = singletonTestService; 17 | _scopedTestService = scopedTestService; 18 | _transientTestService = transientTestService; 19 | } 20 | 21 | [HttpGet("singleton")] 22 | public string GetSingleton() 23 | { 24 | return _singletonTestService.Test(); 25 | } 26 | 27 | [HttpGet("scoped")] 28 | public string GetScoped() 29 | { 30 | return _scopedTestService.Test(); 31 | } 32 | 33 | [HttpGet("transient")] 34 | public string GetTransient() 35 | { 36 | return _transientTestService.Test(); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /tests/Nano.APIExample/Controllers/WeatherForecastController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.Extensions.Logging; 7 | 8 | namespace Nano.APIExample.Controllers 9 | { 10 | [ApiController] 11 | [Route("[controller]")] 12 | public class WeatherForecastController : ControllerBase 13 | { 14 | private static readonly string[] Summaries = new[] 15 | { 16 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 17 | }; 18 | 19 | private readonly ILogger _logger; 20 | 21 | public WeatherForecastController(ILogger logger) 22 | { 23 | _logger = logger; 24 | } 25 | 26 | [HttpGet] 27 | public IEnumerable Get() 28 | { 29 | var rng = new Random(); 30 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 31 | { 32 | Date = DateTime.Now.AddDays(index), 33 | TemperatureC = rng.Next(-20, 55), 34 | Summary = Summaries[rng.Next(Summaries.Length)] 35 | }) 36 | .ToArray(); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /tests/Nano.APIExample/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.HttpsPolicy; 9 | using Microsoft.AspNetCore.Mvc; 10 | using Microsoft.Extensions.Configuration; 11 | using Microsoft.Extensions.DependencyInjection; 12 | using Microsoft.Extensions.Hosting; 13 | using Microsoft.Extensions.Logging; 14 | using Nano.DependencyInjector; 15 | 16 | namespace Nano.APIExample 17 | { 18 | public class Startup 19 | { 20 | public Startup(IConfiguration configuration) 21 | { 22 | Configuration = configuration; 23 | } 24 | 25 | public IConfiguration Configuration { get; } 26 | 27 | // This method gets called by the runtime. Use this method to add services to the container. 28 | public void ConfigureServices(IServiceCollection services) 29 | { 30 | services.RegisterDependencies(Assembly.GetExecutingAssembly()); 31 | services.AddControllers(); 32 | } 33 | 34 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 35 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 36 | { 37 | if (env.IsDevelopment()) 38 | { 39 | app.UseDeveloperExceptionPage(); 40 | } 41 | 42 | app.UseHttpsRedirection(); 43 | 44 | app.UseRouting(); 45 | 46 | app.UseAuthorization(); 47 | 48 | app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: publish to nuget 2 | on: 3 | push: 4 | branches: 5 | - master # Default release branch 6 | jobs: 7 | publish: 8 | name: build, pack & publish 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | # Publish 14 | - name: Publish 15 | id: publish_nuget 16 | uses: rohith/publish-nuget@v2 17 | with: 18 | PROJECT_FILE_PATH: src/Nano.DependencyInjector/Nano.DependencyInjector.csproj 19 | 20 | # NuGet package id, used for version detection & defaults to project name 21 | PACKAGE_NAME: Nano.DependencyInjector 22 | 23 | # Filepath with version info, relative to root of repository & defaults to PROJECT_FILE_PATH 24 | VERSION_FILE_PATH: src/Nano.DependencyInjector/Nano.DependencyInjector.csproj 25 | 26 | # Regex pattern to extract version info in a capturing group 27 | VERSION_REGEX: ^\s*(.*)<\/PackageVersion>\s*$ 28 | 29 | # Useful with external providers like Nerdbank.GitVersioning, ignores VERSION_FILE_PATH & VERSION_REGEX 30 | # VERSION_STATIC: 1.0.0 31 | 32 | # Flag to toggle git tagging, enabled by default 33 | TAG_COMMIT: true 34 | 35 | # Format of the git tag, [*] gets replaced with actual version 36 | # TAG_FORMAT: v* 37 | 38 | # API key to authenticate with NuGet server 39 | NUGET_KEY: ${{secrets.NUGET_API_KEY}} 40 | 41 | # NuGet server uri hosting the packages, defaults to https://api.nuget.org 42 | # NUGET_SOURCE: https://api.nuget.org 43 | 44 | # Flag to toggle pushing symbols along with nuget package to the server, disabled by default 45 | # INCLUDE_SYMBOLS: false 46 | -------------------------------------------------------------------------------- /src/Nano.DependencyInjector/ListExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Nano.DependencyInjector 6 | { 7 | public static class ListExtensions 8 | { 9 | public static ITrue If(this IEnumerable list, Predicate ifStatement) 10 | { 11 | var trueResult = list.Where(i => ifStatement(i)); 12 | var falseResult = list.Where(i => !ifStatement(i)); 13 | 14 | return new IfResult(trueResult, falseResult); 15 | } 16 | } 17 | 18 | public class IfResult : ITrue 19 | { 20 | private readonly IEnumerable trueResult; 21 | private readonly IEnumerable falseResult; 22 | 23 | public IfResult(IEnumerable trueResult, IEnumerable falseResult) 24 | { 25 | this.trueResult = trueResult; 26 | this.falseResult = falseResult; 27 | } 28 | 29 | public IFalse True(Action act) 30 | { 31 | foreach (var item in trueResult) 32 | { 33 | act(item); 34 | } 35 | 36 | return new ElseResult(falseResult); 37 | } 38 | } 39 | 40 | public class ElseResult : IFalse 41 | { 42 | private readonly IEnumerable falseResult; 43 | 44 | public ElseResult(IEnumerable falseResult) 45 | { 46 | this.falseResult = falseResult; 47 | } 48 | 49 | void IFalse.False(Action act) 50 | { 51 | foreach (var item in falseResult) 52 | { 53 | act(item); 54 | } 55 | } 56 | } 57 | 58 | public interface ITrue 59 | { 60 | IFalse True(Action act); 61 | } 62 | 63 | public interface IFalse 64 | { 65 | void False(Action act); 66 | } 67 | } -------------------------------------------------------------------------------- /src/Nano.DependencyInjector/DependencyInjectionConfigure.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace Nano.DependencyInjector 7 | { 8 | internal static class DependencyInjectionConfigure 9 | { 10 | public static List GetDependencies(Assembly assembly) 11 | { 12 | var dependencies = new List(); 13 | foreach (Type type in assembly.GetTypes()) 14 | { 15 | var injectionType = GetInjectionType(type); 16 | 17 | if (!injectionType.HasValue) 18 | { 19 | continue; 20 | } 21 | 22 | dependencies.Add(new DependencyInjectionServiceType() 23 | { 24 | LifeTime = injectionType.Value, 25 | ImplementationType = type, 26 | InterfaceType = 27 | type.GetInterfaces()[ 28 | 0] // TODO (peacecwz): Detect multiple interface and interface inject selection 29 | }); 30 | } 31 | 32 | return dependencies; 33 | } 34 | 35 | private static ServiceLifetime? GetInjectionType(Type type) 36 | { 37 | if (type.GetCustomAttribute() != null) 38 | { 39 | return ServiceLifetime.Singleton; 40 | } 41 | 42 | if (type.GetCustomAttribute() != null) 43 | { 44 | return ServiceLifetime.Scoped; 45 | } 46 | 47 | if (type.GetCustomAttribute() != null) 48 | { 49 | return ServiceLifetime.Transient; 50 | } 51 | 52 | return null; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Nano.DependencyInjector.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D49F7FAA-60A5-4924-B35E-7197530987BB}" 4 | EndProject 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D4271E6C-780C-4B0D-9CEE-C192A0088DCA}" 6 | EndProject 7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nano.DependencyInjector", "src\Nano.DependencyInjector\Nano.DependencyInjector.csproj", "{22D7E784-0B8E-447C-8B79-73C30759A858}" 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nano.APIExample", "tests\Nano.APIExample\Nano.APIExample.csproj", "{DB8AF37A-681B-48CF-8118-7D2E1518A439}" 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nano.DependencyInjector.Tests", "tests\Nano.DependencyInjector.Tests\Nano.DependencyInjector.Tests.csproj", "{13C46E05-D404-4609-A82A-9CDDF653A9A1}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Any CPU = Debug|Any CPU 16 | Release|Any CPU = Release|Any CPU 17 | EndGlobalSection 18 | GlobalSection(NestedProjects) = preSolution 19 | {22D7E784-0B8E-447C-8B79-73C30759A858} = {D49F7FAA-60A5-4924-B35E-7197530987BB} 20 | {DB8AF37A-681B-48CF-8118-7D2E1518A439} = {D4271E6C-780C-4B0D-9CEE-C192A0088DCA} 21 | {13C46E05-D404-4609-A82A-9CDDF653A9A1} = {D4271E6C-780C-4B0D-9CEE-C192A0088DCA} 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {22D7E784-0B8E-447C-8B79-73C30759A858}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {22D7E784-0B8E-447C-8B79-73C30759A858}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {22D7E784-0B8E-447C-8B79-73C30759A858}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {22D7E784-0B8E-447C-8B79-73C30759A858}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {DB8AF37A-681B-48CF-8118-7D2E1518A439}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {DB8AF37A-681B-48CF-8118-7D2E1518A439}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {DB8AF37A-681B-48CF-8118-7D2E1518A439}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {DB8AF37A-681B-48CF-8118-7D2E1518A439}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {13C46E05-D404-4609-A82A-9CDDF653A9A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {13C46E05-D404-4609-A82A-9CDDF653A9A1}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {13C46E05-D404-4609-A82A-9CDDF653A9A1}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {13C46E05-D404-4609-A82A-9CDDF653A9A1}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Nano Dependency Injector 2 | 3 | Easy to apply dependency injection into .NET Core Projects with Attributes like Spring Boot Applications 4 | 5 | ## Installation 6 | 7 | ```bash 8 | dotnet add package Nano.DependencyInjector 9 | ``` 10 | 11 | ## Usage 12 | 13 | Define injection lifetime attribute to your injection class (Singleton, Scoped or Transient) 14 | 15 | ### Singleton Example 16 | 17 | ```cs 18 | public interface ISingletonTestService 19 | { 20 | string Test(); 21 | } 22 | 23 | [Singleton] // Add attribute to service class 24 | public class SingletonTestService : ISingletonTestService 25 | { 26 | public SingletonTestService() 27 | { 28 | Console.WriteLine("Created singleton lifetime instance"); 29 | } 30 | 31 | public string Test() 32 | { 33 | return "Singleton"; 34 | } 35 | } 36 | ``` 37 | 38 | ### Scoped Example 39 | 40 | ```cs 41 | public interface IScopedTestService 42 | { 43 | string Test(); 44 | } 45 | 46 | [Scoped] // Add attribute to service class 47 | public class ScopedTestService : IScopedTestService 48 | { 49 | public ScopedTestService() 50 | { 51 | Console.WriteLine("Created scoped lifetime instance"); 52 | } 53 | 54 | public string Test() 55 | { 56 | return "Scoped"; 57 | } 58 | } 59 | ``` 60 | 61 | ### Transient Example 62 | 63 | ```cs 64 | public interface ITransientTestService 65 | { 66 | string Test(); 67 | } 68 | 69 | [Transient] // Add attribute to service class 70 | public class TransientTestService : ITransientTestService 71 | { 72 | public TransientTestService() 73 | { 74 | Console.WriteLine("Created transient lifetime instance"); 75 | } 76 | 77 | public string Test() 78 | { 79 | return "Transient"; 80 | } 81 | } 82 | ``` 83 | 84 | ### Register Dependencies to IoC 85 | 86 | Add code to ```ConfigureServices``` on Startup.cs file and it will register all dependencies 87 | 88 | ```cs 89 | services.RegisterDependencies(Assembly.GetExecutingAssembly()); 90 | ``` 91 | 92 | ## TODO List 93 | 94 | * [x] Setup CI for publishing package on nuget 95 | * [ ] Add unit tests 96 | * [ ] Register named typed dependency 97 | * [ ] Inject name typed dependency 98 | * [ ] Add property injection without constructor 99 | * [ ] Register injectable multiple interfaces 100 | * [ ] Generic interfaces 101 | 102 | ## Contribution 103 | 104 | Feel the free for contribution. Open issues, PR and contact to me 105 | 106 | ## License 107 | 108 | This project is licensed under the MIT License 109 | -------------------------------------------------------------------------------- /src/Nano.DependencyInjector/NanoDependencyInjectorExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace Nano.DependencyInjector 7 | { 8 | public static class NanoDependencyInjectorExtensions 9 | { 10 | public static IServiceCollection RegisterDependencies(this IServiceCollection services, Assembly assembly) 11 | { 12 | DependencyInjectionConfigure.GetDependencies(assembly) 13 | .If(d => d.HasPropertyInjectAttribute()) 14 | .True(services.AddPropertyInjectableTypes) 15 | .False(f => services.Add( 16 | new ServiceDescriptor(f.InterfaceType, f.ImplementationType, f.LifeTime))); 17 | return services; 18 | } 19 | 20 | private static void SetPropertyValue(IServiceProvider provider, object instance) 21 | { 22 | var injectableProperties = instance.GetType().GetProperties() 23 | .Where(p => p.GetCustomAttribute() != null) 24 | .ToList(); 25 | foreach (var property in injectableProperties) 26 | { 27 | var value = provider.GetService(property.PropertyType); 28 | property.SetValue(instance, value); 29 | } 30 | } 31 | 32 | private static object CreateInstance(IServiceProvider provider, Type type) 33 | { 34 | object instance; 35 | ConstructorInfo publicConstructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, 36 | null, new[] {typeof(string)}, null); 37 | 38 | if (publicConstructor == null) 39 | { 40 | instance = System.Runtime.Serialization.FormatterServices 41 | .GetUninitializedObject(type); 42 | SetPropertyValue(provider, instance); 43 | return instance; 44 | } 45 | 46 | var constructorPareParameters = publicConstructor.GetParameters(); 47 | 48 | if (constructorPareParameters.Any()) 49 | { 50 | var parameterInstances = constructorPareParameters 51 | .Select(parameter => provider.GetRequiredService(parameter.ParameterType)).ToList(); 52 | instance = Activator.CreateInstance(type, parameterInstances); 53 | } 54 | else 55 | { 56 | instance = Activator.CreateInstance(type); 57 | } 58 | 59 | SetPropertyValue(provider, instance); 60 | return instance; 61 | } 62 | 63 | internal static void AddPropertyInjectableTypes(this IServiceCollection services, 64 | DependencyInjectionServiceType dependency) 65 | { 66 | switch (dependency.LifeTime) 67 | { 68 | case ServiceLifetime.Scoped: 69 | services.AddScoped(dependency.InterfaceType, 70 | provider => CreateInstance(provider, dependency.ImplementationType)); 71 | break; 72 | case ServiceLifetime.Singleton: 73 | services.AddSingleton(dependency.InterfaceType, 74 | provider => CreateInstance(provider, dependency.ImplementationType)); 75 | break; 76 | case ServiceLifetime.Transient: 77 | services.AddTransient(dependency.InterfaceType, 78 | provider => CreateInstance(provider, dependency.ImplementationType)); 79 | break; 80 | default: 81 | throw new NotImplementedException(); 82 | } 83 | } 84 | 85 | internal static bool HasPropertyInjectAttribute(this DependencyInjectionServiceType dependency) 86 | { 87 | return dependency.ImplementationType.GetProperties() 88 | .Any(p => p.GetCustomAttribute() != null); 89 | } 90 | } 91 | } --------------------------------------------------------------------------------