Skip to content

Latest commit

 

History

History
247 lines (218 loc) · 8.89 KB

README_CN.md

File metadata and controls

247 lines (218 loc) · 8.89 KB

NAutowired

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

ASP.NET Core 通过属性注入依赖

理念与定位

  • 我们不做容器,我们只是NET Core Container的搬运工(在默认容器的基础上增加了一些功能)。
  • 不要在构造函数中使用NAutowired
  • 由于我们与那些妖艳的第三方IoC Container有些不同,我们没有替换NetCore默认的Container,这意味着您依然可以在Startup里使用IServiceCollection将服务加入到Container并使用NAutowired还原这些依赖。
  • 虽然有人觉得Spring风格的DI有点反模式显式依赖),但是写起来爽。

如何使用

  • nuget包管理器中引入NAutowiredNAutowired.Core
  • NAutowired包应该只在Web或Console项目中被引用,NAutowired.Core包则在需要添加特性的项目中被引用。

ASP.NET Core 3.0

ASP.NET Core 6.0

默认情况下,ASP.NET Core生成Controller时从容器中解析Controller构造函数中的依赖,但是不从容器中还原控制器,这导致:

  • Controller的生命周期由框架处理,而不是请求的生命周期
  • Controller构造函数中参数的生命周期由请求生命周期处理
  • Controller中通过属性注入将不起作用

您必须使用AddControllersAsServices方法,将Controller注册为Service,以便Controller在还原时使用属性注入

Startup.cs中使用AddControllersAsServices并替换IControllerActivator实现为NAutowiredControllerActivator

public void ConfigureServices(IServiceCollection services) {
    //register controllers as services
    services.AddControllers().AddControllersAsServices();
    //replace `IControllerActivator` implement.
    services.Replace(ServiceDescriptor.Transient<IControllerActivator, NAutowiredControllerActivator>());
}

使用Autowired

  public class Startup {
    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services) {
      //将FooService加到容器
      services.AddScoped<FooService>();
      //将多个IBarService实现加到容器
      services.AddScoped<IBarService, MyBarService1>();
      services.AddScoped<IBarService, MyBarService2>();
    }
  }
  [Route("api/[controller]")]
  [ApiController]
  public class FooController : ControllerBase {

    //使用Autowired Attribute注入实例
    [Autowired]
    private readonly FooService fooService;

    //支持注入集合
    [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";
    }
  }

Filter中使用NAutowired

  public class Startup {
    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services) {
      //将Filter加到容器
      services.AddScoped<AuthorizationFilter>();
    }
  }
  //使用 ServiceFilterAttribute
  [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) {
      //将配置文件添加到ioc容器
      services.Configure<SnowflakeConfig>(Configuration.GetSection("Snowflake"));
    }
  }
public class FooController : ControllerBase {
  //使用autowired还原配置
    [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 Console >= 3.0

新建Srartup.cs文件,并且继承自NAutowired.Core.Startup

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

    //程序启动时将会执行此方法
    public override void Run(string[] args)
    {
        System.Console.WriteLine(fooService.Foo());
        System.Console.ReadLine();
    }
}

Program.cs

class Program
{
    static void Main(string[] args)
    {
        ConsoleHost.CreateDefaultBuilder(new List<string> {  "assemblyName" }, args).Build().Run<Startup>();
        //你也可以让NAutowired使用你传递的IServiceCollection
        /*
        ConsoleHost.CreateDefaultBuilder(() => {
          var serviceDescriptors = new ServiceCollection();
          serviceDescriptors.AddTransient<FooService>();
          return serviceDescriptors;
        }, new List<string> { "NAutowiredConsoleSample" }, args).Build().Run<Startup>();
        */
    }
}

单元测试

进阶

您可以通过[Autowired(Type)]方式注入特定的类型

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

    //注入特定的实例
    [Autowired(typeof(FooService))]
    private readonly IService service;

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

NAutowired提供了AutoRegisterDependency方法进行自动容器注入.这种方式让您无需在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.AutoRegisterDependency(new List<string> { "NAutowiredSample" });
    }
  }

使用[Service] [Repository] [Component] [ServiceFilter]特性标记类,这些类将在AutoRegisterDependency执行时被加入到容器

  //默认Lifetime值为Scoped
  [Service]
  //Lifetime可供选择依赖注入的生命周期
  //[Service(Lifetime.Singleton)]
  public class FooService {
  }

  [Service(implementInterface: typeof(IService))]
  //注入特定的实现类到容器。这将执行services.AddScoped(typeof(IService), typeof(FooService));
  public class FooService: IService {
  }

NAutowired会自动扫描AutoRegisterDependency(assemblyNames)方法配置的程序集下的所有类,并将具有[Service] [Repository] [Component] [ServiceFilter]特性的类注入到容器。

NAutowired提供了WithAutowiredGetServiceWithAutowired扩展方法,可以从容器中获取服务,并自动解析其[Autowired]依赖。在需要手动获取服务或者解析现有实例时使用这些方法尤为方便。

services.AddSingleton(sp =>
{
    var foo = sp.GetServiceWithAutowired<IFooService>();
    return foo.Create();
});

Stargazers over time

Stargazers over time