jrt324 / NAutowired

ASP.NET CORE Field Injection Implement

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

NAutowired

NuGet NuGet GitHub issues GitHub repo size in bytes GitHub top language

ASP.NET CORE Field Injection

Idea and positioning

  • We don't make containers, we are just porters of NetCore Container (add some features to the default container).
  • Don't use NAutowired in the constructor.
  • We have not replaced NetCore default Container, which means you can still add services to Container using IServiceCollection in Startup. And use NAutowired to resolve dependencies.
  • Spring DI style is ugly(Explicit dependencies), but who cares?

How to use

  • Introducing NAutowired and NAutowired.Core in the nuget.
  • The NAutowired package should only be referenced in the web project, and the NAutowired.Core package is referenced in projects that need to add features.

ASP.NET Core 3.0

By default, when ASP.NET Core generates Controller, dependencies in the Controller constructor are resolved from the container, but the controller is not resolved from the container, which results in:

  • The lifetime of the Controller is handled by the framework, not the lifetime of the request
  • The lifetime of parameters in the Controller constructor is handled by the request lifetime
  • In Controller use Field Injection won’t work

You must use the AddControllersAsServices method to register the Controller as a Service so that the Controller can use the Field Injection when resolve. Use AddControllersAsServices in Startup.cs and replace IControllerActivator as NAutowiredControllerActivator.

Replace the default IControllerActivator implementation with NAutowiredControllerActivator in Startup.cs

public void ConfigureServices(IServiceCollection services) {
    //register controllers as services
    services.AddControllers().AddControllersAsServices();
    //replace `IControllerActivator` implement.
    services.Replace(ServiceDescriptor.Transient<IControllerActivator, NAutowiredControllerActivator>());
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) {
    //Add FooService to container.
    services.AddScoped<FooService>();
}
  [Route("api/[controller]")]
  [ApiController]
  public class FooController : ControllerBase {

    //Use Autowired injection.
    [Autowired]
    private readonly FooService fooService;

    [HttpGet]
    public ActionResult<string> Get() {
      return fooService == null ? "failure" : "success";
    }
  }

Use in Filter

  public class Startup {
    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services) {
      //Add Filter to container.
      services.AddScoped<AuthorizationFilter>();
    }
  }
  //Use ServiceFilter like ASP.NET CORE ServiceFilter.
  [NAutowired.Attributes.ServiceFilter(typeof(AuthorizationFilter))]
  public class FooController : ControllerBase {

  }
  public class AuthorizationFilter : IAuthorizationFilter {
    [Autowired]
    private readonly FooService fooService;

    public void OnAuthorization(AuthorizationFilterContext context) {
      System.Console.WriteLine($"{fooService.ToString()} in filter");
      return;
    }
  }

Get Configuration

  public class Startup {
    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services) {
      //add config to ioc container
      services.Configure<SnowflakeConfig>(Configuration.GetSection("Snowflake"));
    }
  }
public class FooController : ControllerBase {
  //use autowired get configuration
    [Autowired]
    private IOptions<SnowflakeConfig> options { get; set; }

    [HttpGet("snowflake")]
    public IActionResult GetSnowflakeConfig()
    {
        return Ok(options.Value);
    }
}

SnowflakeConfig.cs

public class SnowflakeConfig
{
    public int DataCenter { get; set; }

    public int Worker { get; set; }
}

appsettings.json

{
  "Snowflake": {
    "DataCenter": 1,
    "Worker": 1
  }
}

NET Core 3.0 Console

Create a new Srartup.cs file and inherit from NAutowired.Core.Startup

public class Startup : NAutowired.Core.Startup
{
    [Autowired]
    private readonly FooService fooService;

    //Program start up func
    public override void Run(string[] args)
    {
        System.Console.WriteLine(fooService.Foo());
        System.Console.ReadLine();
    }
}

In Program.cs

class Program
{
    static void Main(string[] args)
    {
        ConsoleHost.CreateDefaultBuilder(new List<string> {  "assemblyName" }, args).Build().Run<Startup>();
        //You can also let NAutowired use the IServiceCollection you passed
        /*
        ConsoleHost.CreateDefaultBuilder(() => {
          var serviceDescriptors = new ServiceCollection();
          serviceDescriptors.AddTransient<FooService>();
          return serviceDescriptors;
        }, new List<string> { "NAutowiredConsoleSample" }, args).Build().Run<Startup>();
        */
    }
}

Unit Test

Advanced

You can inject a specific type with the [Autowired(Type)] method

  [Route("api/[controller]")]
  [ApiController]
  public class FooController : ControllerBase {

    //Inject a specific instance.
    [Autowired(typeof(FooService))]
    private readonly IFooService fooService;

    [HttpGet]
    public ActionResult<string> Get() {
      return fooService == null ? "failure" : "success";
    }
  }

NAutowired provides the AutoRegisterDependency(assemblyName) method for automatic container injection. This way you don't need to add the type to the container one by one in Startup.cs

  public class Startup {
    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services) {
      //services.AddScoped<FooService>();
      //Use automatic injection.
      services.AutoRegisterDependency(new List<string> { "NAutowiredSample" });
    }
  }

Use the [Service] [Repository] [Component] [ServiceFilter] attribute tag class, these classes will be added to the container when AutoRegisterDependency is executed

  //The default Lifetime value is Scoped
  [Service]
  //Lifetime to choose the life cycle of dependency injection
  //[Service(Lifetime.Singleton)]
  public class FooService {
  }

  [Service(implementInterface: typeof(IService))]
  //injection interface to container like services.AddScoped(typeof(IService), typeof(FooService));
  public class FooService: IService {
  }

NAutowired will automatically scan all classes under the assembly configured by the AddAutoDependencyInjection(assemblyName) method, and inject the class with the [Service] [Repository] [Component] [ServiceFilter] property into the container.

About

ASP.NET CORE Field Injection Implement

License:MIT License


Languages

Language:C# 99.2%Language:Batchfile 0.8%