欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C#笔记2 依赖注入—服务的生命周期

程序员文章站 2023-12-28 11:40:28
...


示例用到的包和命名空间


Microsoft.Extensions.DependencyInjection

命名空间
Microsoft.Extensions.DependencyInjection

使用单例和临时服务

RegisterServices在方法SingletonAndTransient中作为本地函数实现。其中注册了ServiceAServiceBNumberService和控制器类ControllerXNumberServiceServiceA注册为单例ServiceBControllerX注册为瞬态

public static void SingletonAndTransient()
{
    Console.WriteLine(nameof(SingletonOrTransient));   
    static ServiceProvider RegisterService()
    {
                
        IServiceCollection services = new ServiceCollection();
        services.AddSingleton<IServiceA, ServiceA>();
        services.AddTransient<IServiceB, ServiceB>();
        services.AddTransient<ControllerX>();
        services.AddSingleton<INumberService, NumberService>();
        return services.BuildServiceProvider();
    }
    //TODO
}

AddSingletonAddTransient都是扩展方法,更便于用Microsoft.Extensions.DependencyInjection框架注册服务。除了这些有用的方法之外,还可以使用Add方法注册。Add方法需要一个包含服务类型,实现类型和服务种类的ServiceDescriptor加粗样式。服务的种类使用ServiceLifetime枚举类型指定。ServiceLifetime定义了值SingletonTransientScoped

注意
ServiceCollection类的Add方法是为接口IServiceCollection显示实现的。对于这个,只能在使用接口IServiceCollection时才能看到方法,使用ServiceCollection类型的对象时是看不到他的。

使用Scope服务

服务也可以在一个作用域内注册,这是介于SingletonTransient之间的服务。Singleton之创建一个实例,Transient每次请求服务都会创建一个新实例。对于Scope,总是从相同的作用域中返回相同的实例,但是从不同的作用域中会返回不同的实例。作用域默认用ASP.NET Core Web应用程序定义。这里,作用域是个HTTP Web请求。对于Scope服务,如果对容器的请求来自同一个HTTP请求,则返回相同的实例;如果来自不同的HTTP请求,则返回不同是实例。这允许在HTTP请求中轻松的 共享状态。

对于非ASP.NET Core Web应用程序,需要自己创建作用域,以获得Scope服务的优势。

private static void UsingScope()
{
	ServiceProvider RegisterServices()
	{
		var services = new ServiceCollection();
		services.AddSingleton<INumberService, NumberService>();
		services.AddScoped<IServiceA,ServiceA>();
        services.AddSingleton<IServiceB, ServiceB>();
        services.AddTransient<IServiceC, ServiceC>();
	}
	//TODO
}

调用ServiceProvider的CreateScope方法可以创建一个作用域。这将返回实现接口IServiceScope的作用域对象,在其中可以访问属于这个作用域的ServiceProvider,可以在容器中请求服务。

private static void UsingScope()
{
	//TODO
	using(ServiceProvider container = RegisterServices())
	{
		using(IServiceScope scope = container.CreateScope())
		{
			IserviceA a1 = scope.ServiceProvider.GetService<IServiceA>();
			//TODO
		}
	}
}

注意:
不需要在服务上调用Dispose方法来释放它们,使用实现了IDispose接口的服务,容器会调用Dispose方法。当释放作用域时,将释放Transient服务和Scoped服务。在释放根提供程序时,将释放Singleton服务。

在.Net Core 2.0中,服务实例按照创建的相反顺序来释放,当一个服务需要注入另一个服务时这很重要。

使用自定义工厂或传递现有实例

除了定义使用transientscopedsingleton之外,还可以创建自定义工厂或者将现有实例传递给容器。

  • 可以使用AddSingleton方法的重载版本,将先前创建的实例传递给容器。这里,在RegisterServices方法中,首先创建一个NumberService对象,然后将其传递给AddSingleton方法。使用GetService方法,或者在构造函数中注入它,与前面的的代码没什么不同。只需要注意,在本例中,容器不负责调用Dispose方法。对于创建并传递到容器中的服务,应由开发人员手动释放(如果需要释放)。
  • 还可以使用工厂方法来创建实例,而不是从容器中创建服务。如果服务需要自定义的初始化,或者定义不受DI容器支持的构造函数,这是一个有用的选项。可以通过IServiceProvider参数传递委托,并将服务实例返回到AddSingletonAddScopedAddTransient方法。
public static void CustomFactories()
{
    Console.WriteLine(nameof(CustomFactories));

    IServiceB CreateServiceFactory(IServiceProvider serviceProvider) 
        => new ServiceB(serviceProvider.GetService<INumberService>());
    ServiceProvider RegisterService()
    {
        var numberService = new NumberService();
        IServiceCollection services = new ServiceCollection();
        services.AddSingleton(numberService);// use a existing
        services.AddTransient(CreateServiceFactory);// use a custom factory
        return services.BuildServiceProvider();
    }
}

上一篇:

下一篇: