我想在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>();
}
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,我强烈推荐《依赖注入原则、实践和模式》一书。我的答案基本上只是重复我在那里学到的东西。
在寻找这个问题的答案后,我找到了一个很好的解释,并列举了一个我想与大家分享的例子。
您可以在此处观看演示差异的视频
在此示例中,我们有以下给定代码:
public interface IEmployeeRepository
{
IEnumerable<Employee> GetAllEmployees();
Employee Add(Employee employee);
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
public class MockEmployeeRepository : IEmployeeRepository
{
private List<Employee> _employeeList;
public MockEmployeeRepository()
{
_employeeList = new List<Employee>()
{
new Employee() { Id = 1, Name = "Mary" },
new Employee() { Id = 2, Name = "John" },
new Employee() { Id = 3, Name = "Sam" },
};
}
public Employee Add(Employee employee)
{
employee.Id = _employeeList.Max(e => e.Id) + 1;
_employeeList.Add(employee);
return employee;
}
public IEnumerable<Employee> GetAllEmployees()
{
return _employeeList;
}
}
家庭控制器
public class HomeController : Controller
{
private IEmployeeRepository _employeeRepository;
public HomeController(IEmployeeRepository employeeRepository)
{
_employeeRepository = employeeRepository;
}
[HttpGet]
public ViewResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create(Employee employee)
{
if (ModelState.IsValid)
{
Employee newEmployee = _employeeRepository.Add(employee);
}
return View();
}
}
创建视图
@model Employee
@inject IEmployeeRepository empRepository
<form asp-controller="home" asp-action="create" method="post">
<div>
<label asp-for="Name"></label>
<div>
<input asp-for="Name">
</div>
</div>
<div>
<button type="submit">Create</button>
</div>
<div>
Total Employees Count = @empRepository.GetAllEmployees().Count().ToString()
</div>
</form>
启动.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<IEmployeeRepository, MockEmployeeRepository>();
}
复制粘贴此代码,然后按视图中的创建按钮,然后在AddSingleton、AddScoped和AddTransient每次都会得到不同的结果,这可能会帮助您理解这一点。
AddSingleton()-顾名思义,AddSingletton()方法创建单人服务。Singleton服务在首次创建时创建请求。然后,所有后续的请求。所以一般来说,Singleton服务只创建一次每个应用程序,并且在整个应用寿命。AddTransient()-此方法创建一个Transient服务。一个新的每次请求瞬态服务时都会创建该服务的实例。AddScoped()-此方法创建作用域服务。的新实例作用域内的每个请求创建一次作用域服务。对于例如,在web应用程序中,它为每个http创建一个实例请求,但在同一调用中的其他调用中使用同一实例web请求。