ASP.NET CORE Field Injection
- We don't make containers, we are just porters of
NetCore Container(add some features to the default container). - Don't use
NAutowiredin the constructor. - We have not replaced
NetCoredefaultContainer, which means you can still add services toContainerusingIServiceCollectioninStartup. And useNAutowiredto resolve dependencies. - Spring DI style is ugly(Explicit dependencies), but who cares?
- Introducing
NAutowiredandNAutowired.Corein the nuget. - The
NAutowiredpackage should only be referenced in the web project, and theNAutowired.Corepackage is referenced in projects that need to add features.
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
Controlleris handled by the framework, not the lifetime of the request - The lifetime of parameters in the
Controllerconstructor is handled by the request lifetime - In
ControlleruseField Injectionwon’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>();
//Add IBarService implements to container.
services.AddScoped<IBarService, MyBarService1>();
services.AddScoped<IBarService, MyBarService2>();
} [Route("api/[controller]")]
[ApiController]
public class FooController : ControllerBase {
//Use Autowired injection.
[Autowired]
private readonly FooService fooService;
//Also supports IEnumerable<T> injection.
[Autowired]
private readonly IEnumerable<IBarService> barServices;
[HttpGet]
public ActionResult<string> Get() {
return fooService == null ? "failure" : "success";
}
[HttpPost]
public ActionResult<string> Baz() {
return barServices?.Count > 0 ? "success" : "failure";
}
} 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;
}
} 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
}
}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();
}
}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>();
*/
}
} [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 AutoRegisterDependency(assemblyName) method, and inject the class with the [Service] [Repository] [Component] [ServiceFilter] property into the container.
NAutowired provides WithAutowired、GetServiceWithAutowired extension methods,which can obtain services from containers and automatically resolve their [Autowired] dependencies. It's particularly convenient when you need to manually obtain services or resolve existing instances.
services.AddSingleton(sp =>
{
var foo = sp.GetServiceWithAutowired<IFooService>();
return foo.Create();
});