zijian666.DI.Autowired 1.1.0.15-beta

This is a prerelease version of zijian666.DI.Autowired.
dotnet add package zijian666.DI.Autowired --version 1.1.0.15-beta
NuGet\Install-Package zijian666.DI.Autowired -Version 1.1.0.15-beta
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="zijian666.DI.Autowired" Version="1.1.0.15-beta" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add zijian666.DI.Autowired --version 1.1.0.15-beta
#r "nuget: zijian666.DI.Autowired, 1.1.0.15-beta"
#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 zijian666.DI.Autowired as a Cake Addin
#addin nuget:?package=zijian666.DI.Autowired&version=1.1.0.15-beta&prerelease

// Install zijian666.DI.Autowired as a Cake Tool
#tool nuget:?package=zijian666.DI.Autowired&version=1.1.0.15-beta&prerelease

Autowired自动装配

仿 Java Spring 自动装配特性 @Autowired
自动处理 循环引用、GetServices、类型转换 等情况

* 特别说明:不确定类型的泛型服务 无法使用自动装配,请使用手动装配的方式完成功能
* 如services.AddSingleton(typeof(MyService2<>));

1. 自动装配

Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) =>
    {
        services.AddSingleton<MyService1>();
        services.AddSingleton<MyService2>();
        ...
        services.AddAutowired()  // 必须在所有服务注入之后再调用,否则将不会作用于后续注入服务
    }
    .RunConsoleAsync();

2 手动装配

/// <summary>
/// 自动装配
/// </summary>
/// <param name="services">服务提供程序</param>
/// <param name="instance">待装配的实例对象</param>
/// <param name="serviceType">声明服务类型, 可空</param>
public static T Autowired<T>(this IServiceProvider services, T instance, Type? serviceType = null)
构造函数装配
class MyService1
{
    [Autowired]
    public MyService[] field_1;

    public MyService1(IServiceProvider services)
    {
        services.Autowired(this);
    }
}
单独注入装配
new ServiceCollection()
   .AddTransient<MyService1>(p => p.Autowired(ActivatorUtilities.CreateInstance<MyService1>(p)))
   .BuildServiceProvider();

3 在单例服务中装配Scoped服务

[Component(Lifetime = ServiceLifetime.Singleton)]
class MyServiceSingleton
{
    [Autowired]
    public ScopedServiceProvider ServiceProvider;
}


using var scope = root.CreateScope();
var services = scope.ServiceProvider;
//  var singleton = services.GetService<MyServiceSingleton>();
// 使用常规方式 ScopedServiceProvider 只能获取root范围的 IServiceProvider
// 这是官方机制所决定的,目前没有更好的解决方案,详见 **# 已知问题** 章节

var singleton = services.GetServiceWithScope<MyServiceSingleton>(); // 使用这个扩展方法,可以正确注入 Scoped 作用域的 IServiceProvider

这种行为虽然有点反设计,但在实际业务场景中确实存在:
例如:数据库实例作为Scoped服务,需要在一个单例服务(如一个全局唯一的轮询健康检查服务中检查数据库情况)

已知问题

在注入 IServiceProvider 时,标准的构造函数注入的方式,会根据服务本身的生命周期注入不同的IServiceProvider
该行为无法模拟,属于已知但目前无法解决的问题,
1.0.11 版增加3个代替IServerProvider的类型:
SingletonServiceProviderScopedServiceProviderTransientServiceProvider
用于控制IServiceProvider注入行为

对于IServiceProvider这个特殊的服务,会出现一个服务存在三种不同生命周期的情况; 在不同的scope中,存在不同的实例。
[Autowired] 核心逻辑还是通过 IServiceProvider.GetService 获取服务实例,然后反射赋值到属性或字段上。
IServiceProvider 这个服务,只有在构造函数注入时才能根据服务的生命周期,获得准确的实例对象。
在使用[Autowired]注入时可能存在问题。如下面这个例子:

class MyServiceTransient
{
    [Autowired]
    public IServiceProvider ServiceProvider;

    [Autowired]
    public MyServiceSingleton ServiceSingleton;
}
class MyServiceSingleton
{
    [Autowired]
    public IServiceProvider ServiceProvider;

    [Autowired]
    public MyServiceTransient ServiceTransient;
}


var root = new ServiceCollection()
    .AddTransient<MyServiceTransient>()
    .AddSingleton<MyServiceSingleton>()
    .AddAutowired()
    .BuildServiceProvider();

using var scope = root.CreateScope();
var services = scope.ServiceProvider;

var transient = services.GetService<MyServiceTransient>();
var singleton = services.GetService<MyServiceSingleton>();

// 这里按照预期,应该是不相等的,但实际在使用 Autowired 注入时,会相等
Console.WriteLine(transient.ServiceProvider == singleton.ServiceProvider); // true
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on zijian666.DI.Autowired:

Package Downloads
zijian666.WebApiExtensions

用于快速创建简单易用的标准化WebApi项目

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.1.0.15-beta 59 6/24/2024
1.0.12-beta 124 7/22/2023
1.0.11-beta 115 7/20/2023
1.0.9 174 7/16/2023
1.0.8 120 7/14/2023
1.0.7 198 4/7/2023
1.0.6 390 6/10/2022
1.0.4 378 6/9/2022

UPLOGS.md