Asp.net mvc 为什么asp.net core支持几种注册服务的方法?

Asp.net mvc 为什么asp.net core支持几种注册服务的方法?,asp.net-mvc,asp.net-core,Asp.net Mvc,Asp.net Core,我将从classStudent创建一个服务StudentData: public interface IStudentData { List<Student> GetAll(); } public class StudentData : IStudentData { public List<Student> GetAll() { var students = new List<Student> {

我将从class
Student
创建一个服务
StudentData

public interface IStudentData
{
    List<Student> GetAll();
}

public class StudentData : IStudentData
{
    public List<Student> GetAll()
    {
        var students = new List<Student>
        {
            new Student { FirstName = "Harry", LastName = "Potter" },
            new Student { FirstName = "Hermione", LastName = "Granger" }
        };

        return students;
    }
}

public class Student
{
    public int Id { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }        
}
公共接口是学生数据
{
List GetAll();
}
公共班级学生数据:IStudentData
{
公共列表GetAll()
{
var students=新列表
{
新学生{FirstName=“Harry”,LastName=“Potter”},
新学生{FirstName=“赫敏”,LastName=“格兰杰”}
};
留学生;
}
}
公立班学生
{
公共int Id{get;set;}
公共字符串名{get;set;}
公共字符串LastName{get;set;}
}
以下是注册服务的一些方法:

services.AddTransient<IStudentData, StudentData>();
services.AddTransient(typeof(IStudentData), typeof(StudentData));
services.Add(new ServiceDescriptor(typeof(IStudentData), typeof(StudentData), ServiceLifetime.Transient));
services.Add(new ServiceDescriptor(typeof(IStudentData), p => new StudentData(), ServiceLifetime.Transient));

services.AddSingleton<IStudentData, StudentData>();
services.AddSingleton(typeof(IStudentData), typeof(StudentData));
services.Add(new ServiceDescriptor(typeof(IStudentData), typeof(StudentData), ServiceLifetime.Singleton));
services.Add(new ServiceDescriptor(typeof(IStudentData), p => new StudentData(), ServiceLifetime.Singleton));

services.AddScoped<IStudentData, StudentData>();
services.AddScoped(typeof(IStudentData), typeof(StudentData));
services.Add(new ServiceDescriptor(typeof(IStudentData), typeof(StudentData), ServiceLifetime.Scoped));
services.Add(new ServiceDescriptor(typeof(IStudentData), p => new StudentData(), ServiceLifetime.Scoped));

services.AddInstance<IStudentData>(new StudentData());
services.AddInstance(typeof(IStudentData), new StudentData());        
services.Add(new ServiceDescriptor(typeof(IStudentData), new StudentData()));
services.AddTransient();
AddTransient(typeof(IStudentData)、typeof(StudentData));
添加(新的ServiceDescriptor(typeof(IStudentData)、typeof(StudentData)、ServiceLifetime.Transient));
Add(新的ServiceDescriptor(typeof(IStudentData),p=>newstudentData(),ServiceLifetime.Transient));
services.AddSingleton();
AddSingleton(typeof(IStudentData)、typeof(StudentData));
Add(新的ServiceDescriptor(typeof(IStudentData)、typeof(StudentData)、ServiceLifetime.Singleton));
Add(新的ServiceDescriptor(typeof(IStudentData),p=>newstudentData(),ServiceLifetime.Singleton));
services.addScope();
addScope(typeof(IStudentData),typeof(StudentData));
添加(新的ServiceDescriptor(typeof(IStudentData)、typeof(StudentData)、ServiceLifetime.Scoped));
Add(新的ServiceDescriptor(typeof(IStudentData),p=>newstudentData(),ServiceLifetime.Scoped));
services.AddInstance(new StudentData());
AddInstance(typeof(IStudentData),newstudentdata());
Add(新的ServiceDescriptor(typeof(IStudentData),newstudentdata());
那么,什么时候使用第一个/第二个/第三个


子问题:是否有其他方法注册服务?

您可以在此处找到有关依赖项注入的更多信息:


例如:Singleton,意味着您将创建一次服务,然后在应用程序的所有生命周期中使用同一实例。有多种方法配置同一事物的原因仅仅是为了方便,并使其在C语言范围内具有灵活性和描述性

// These are the same, you're just specifying the types and the lifetime:
services.AddTransient<IStudentData, StudentData>();
services.AddTransient(typeof(IStudentData), typeof(StudentData));
我将以您给出的最后一个示例(就在上面)为例,解释一个简单的用例来展示它的灵活性:

假设类
StudentData
接受当前
HttpContext
作为构造函数参数(它是类的依赖项)。我可以对其进行配置,以便每当类型为
IStudentData
的实例解析为
StudentData
时,都可以使用传递到构造函数中的当前HttpContext解析它

// Passing in the current HttpContext into StudentData
services.Add(new ServiceDescriptor(typeof(IStudentData), p => new StudentData(HttpContext.Current), ServiceLifetime.Transient));
但它不仅限于传递特定的值,还可以提供任何返回类实例(工厂)的方法——因此可能性是无穷的(某种程度上)


在配置依赖项时,没有正确或错误的选项可供选择,但我建议您选择最清楚配置内容的选项。

一般经验法则是,如果您在编译时知道类型,请使用通用版本
services.AddTransient()

如果在编译之前不知道类型,即通过反射遍历程序集并获取实现某个接口的所有类型,则使用非泛型版本,因为在这种情况下不能使用泛型

foreach(var type in GetAllOfSomeInterface()) {
    services.AddTransient(typeof(ISomeInterface), type);
}
当您需要一个factory方法来解析无法通过DI解析的内容时,请使用
Func
函数,即当应用程序启动时确定的设置或选项,并且您不能使用
IOptions
(即第三方库,其中您不能更改类以接受选项DI模式)


使用
服务。当您创建自己的依赖注入系统及其重载时,或者当您需要动态确定作用域(瞬态、作用域或单例)时,通常在包装现有IoC容器时使用添加。不过,你很少使用它

这个问题的答案是,标记为快速看一眼就可以结束。@Luke,你确定吗?对于
Transient
,我给出了4个案例来使用它,但文档没有分类。请在结束之前阅读问题。我点击了链接并搜索“Transient”,它给出了
AddTransient
的完整说明。这里有一个永久链接,说明文档的这一部分
AddInstance
不是有效选项。有
Singleton
Scoped
Transient
AddTransient
。这就是我想分类的原因。好吗?我通常使用
ApplicationDbContext
作为参数,但它在控制器中,而不是
Startup.cs
中。谢谢顺便说一句,ASP.NET中没有
HttpContext.Current
Core@Tseng谢谢,这是个坏例子。我对ASP.NET内核还不是很了解:)@HappyCoding我希望这个答案对你有用。是的,代替HttpContext,DbContext的实例也可以工作,或者任何类或值。更多:asp.net core有了新的概念
设计时
(使用
Ctrl+S
而不是
Ctrl+Shift+B
来构建项目):@happyCodeing:这不是重点。当您键入接口和类时,您在构建之前就知道了它。当您遍历程序集时,您不会。运行时不能将泛型与
类型一起使用,这意味着这是无效的:
服务.AddTransient()
服务.AddTransient()
,这就是为什么需要将其作为参数传递。
服务.AddIdentity().AddEntityFrameworkStores().AddDefaultTokenProviders()我刚刚根据您的答案对数据库进行了一些修改。谢谢
foreach(var type in GetAllOfSomeInterface()) {
    services.AddTransient(typeof(ISomeInterface), type);
}