我想在ASP.NET Core中实现依赖注入(DI)。因此,在将此代码添加到ConfigureServices方法后,这两种方法都可以工作。
ASP.NET Core中的services.AddTransient和service.AddScoped方法之间有什么区别?
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddScoped<IEmailSender, AuthMessageSender>();
}
当必须注入同一类型的多个对象时,ASP.NET MVC核心DI(依赖注入)中的瞬时、作用域和单例定义对象创建过程。如果你是依赖注入的新手,你可以看到这个DI-IoC视频。
您可以看到下面的控制器代码,其中我在构造函数中请求了两个“IDal”实例。Transient、Scoped和Singleton定义了同一个实例是否将以“_dal”和“_dal1”或不同的方式注入。
public class CustomerController : Controller
{
IDal dal = null;
public CustomerController(IDal _dal,
IDal _dal1)
{
dal = _dal;
// DI of MVC core
// inversion of control
}
}
瞬态:在瞬态中,将在单个请求和响应中注入新的对象实例。下面是我显示GUID值的快照图像。
作用域:在作用域中,相同的对象实例将被注入到单个请求和响应中。
Singleton:在Singleton中,将在所有请求和响应中注入相同的对象。在这种情况下,将创建对象的一个全局实例。
下面是一个简单的图表,直观地解释了上述基本原理。
上图是我在孟买参加ASP.NET MVC培训时,SBSS团队绘制的。非常感谢SBSS团队创建了上述图像。
DI容器一开始可能非常神秘,特别是在使用寿命方面。毕竟,容器使用反射使一切“正常工作”。这有助于思考容器在幕后为您实际完成的任务:构建对象图。
对于.NET web应用程序,使用DI容器的替代方法是用您自己的控制器激活器替换默认控制器激活器,它必须手动管理生存期并构建依赖关系图。出于学习目的,假设您有一个硬编码的控制器激活器,以便每次有web请求时返回一个特定的控制器:
// This class is created once per application during startup. In DI terms, it is the
// "composition root."
public class DumbControllerActivator
{
// Shared among all consumers from all requests
private static readonly Singleton1 singleton1 = new Singleton1();
private static readonly Singleton2 singleton2 = new Singleton2();
// This method's responsibility is to construct a FooController and its dependecies.
public FooController HandleFooRequest()
{
// Shared among all consumers in this request
var scoped1 = new Scoped1();
var scoped2 = new Scoped2(singleton1, scoped1);
return new FooController(
singleton1,
scoped1,
new Transient1( // Fresh instance
singleton2,
new Transient2(scoped2)), // Fresh instance
new Transient3( // Fresh instance
singleton1,
scoped1,
new Transient1( // Fresh instance
singleton2,
new Transient2(scoped2))); // Fresh instance
}
}
激活器只创建每个单例实例一次,然后在应用程序的整个生命周期中保存它。每个使用者共享一个实例(甚至来自不同请求的使用者)。对于作用域依赖项,激活器为每个web请求创建一个实例。在该请求中,每个使用者共享一个实例,但从一个请求到另一个请求,实例是不同的。对于暂时依赖关系,每个使用者都有自己的私有实例。根本没有共享。
要深入了解DI,我强烈推荐《依赖注入原则、实践和模式》一书。我的答案基本上只是重复我在那里学到的东西。
当必须注入同一类型的多个对象时,ASP.NET MVC核心DI(依赖注入)中的瞬时、作用域和单例定义对象创建过程。如果你是依赖注入的新手,你可以看到这个DI-IoC视频。
您可以看到下面的控制器代码,其中我在构造函数中请求了两个“IDal”实例。Transient、Scoped和Singleton定义了同一个实例是否将以“_dal”和“_dal1”或不同的方式注入。
public class CustomerController : Controller
{
IDal dal = null;
public CustomerController(IDal _dal,
IDal _dal1)
{
dal = _dal;
// DI of MVC core
// inversion of control
}
}
瞬态:在瞬态中,将在单个请求和响应中注入新的对象实例。下面是我显示GUID值的快照图像。
作用域:在作用域中,相同的对象实例将被注入到单个请求和响应中。
Singleton:在Singleton中,将在所有请求和响应中注入相同的对象。在这种情况下,将创建对象的一个全局实例。
下面是一个简单的图表,直观地解释了上述基本原理。
上图是我在孟买参加ASP.NET MVC培训时,SBSS团队绘制的。非常感谢SBSS团队创建了上述图像。
通过DbContext使用EntityFramework/Core可能是生命周期的最佳说明。
建议将DbContext和与DbContext交互的存储库连接到Scoped生存期,因为DbContext显然是一个有状态的构造。所以你不想使用Singleton,因为你最终会遇到各种并发问题。您不想使用Transient,因为DbContext不是线程安全的。记住,Transient适用于处理无状态对象/类的用例。
而且,由于大多数存储库都是由控制器调用的,所以使用作用域生存期确实很有意义。可以想象,作为事务的一部分,DbContext可以在单个操作方法期间多次调用。
本文没有直接讨论这些生存期,但对为什么Scoped生存期最适合DbContext给出了很好的解释。
https://mehdi.me/ambient-dbcontext-in-ef6/?msclkid=00251b05d01411ec8d85d232374f26d5