三、在中间件类型构造函数中注入
ASP.NET Core请求处理管道最重要的对象是用来真正处理请求的中间件。
由于ASP.NET Core在创建中间件对象并利用它们构建整个请求处理管道时,所有的服务都已经注册完毕,所以任何一个注册的服务都可以注入中间件类型的构造函数中。
如下所示的代码片段体现了针对中间件类型的构造函数注入。
class Program { static void Main() { Host.CreateDefaultBuilder().ConfigureWebHostDefaults(builder => builder .ConfigureServices(svcs => svcs .AddSingleton<studentschoolMiddleware>() .AddSingleton<IStudent, student>() .AddSingleton<ISchool, school>()) .Configure(app => app.UseMiddleware<studentschoolMiddleware>())) .Build() .Run(); } } public class studentschoolMiddleware : IMiddleware { public studentschoolMiddleware(IStudent student, ISchool school) { Debug.Assert(student != null); Debug.Assert(school != null); } public Task InvokeAsync(HttpContext context, RequestDelegate next) { Debug.Assert(next != null); return Task.CompletedTask; } }
四、在中间件类型的Invoke/InvokeAsync方法中注入
如果采用基于约定的中间件类型定义方式,注册的服务还可以直接注入真正用于处理请求的InvokeAsync方法或者Invoke方法中。
另外,将方法命名为InvokeAsync更符合TAP(Task-based Asynchronous Pattern)编程模式,之所以保留Invoke方法命名,主要是出于版本兼容的目的。
如下所示的代码片段展示了针对InvokeAsync方法的服务注入。
class Program { static void Main() { Host.CreateDefaultBuilder().ConfigureWebHostDefaults(builder => builder .ConfigureServices(svcs => svcs .AddSingleton<IStudent, student>() .AddSingleton<ISchool, school>()) .Configure(app => app.UseMiddleware<studentschoolMiddleware>())) .Build() .Run(); } } public class studentschoolMiddleware { private readonly RequestDelegate _next; public studentschoolMiddleware(RequestDelegate next) => _next = next; public Task InvokeAsync(HttpContext context, IStudent student, ISchool school) { Debug.Assert(context != null); Debug.Assert(student != null); Debug.Assert(school != null); return _next(context); } }
对于基于约定的中间件,构造函数注入与方法注入存在一个本质区别。
由于中间件被注册为一个Singleton对象,所以我们不应该在它的构造函数中注入Scoped服务。
Scoped服务只能注入中间件类型的InvokeAsync方法中,因为依赖服务是在针对当前请求的服务范围中提供的,所以能够确保Scoped服务在当前请求处理结束之后被释放。
五、在Controller类型的构造函数中注入
在一个ASP.NET Core MVC应用中,我们可以在定义的Controller中以构造函数注入的方式注入所需的服务。
在如下所示的代码片段中,我们将IStudentschool服务注入到HomeController的构造函数中。
class Program { static void Main() { Host.CreateDefaultBuilder().ConfigureWebHostDefaults(builder => builder .ConfigureServices(svcs => svcs .AddSingleton<IStudentschool, studentschool>() .AddSingleton<ISchool, school>() .AddControllersWithViews()) .Configure(app => app .UseRouting() .UseEndpoints(endpoints => endpoints.MapControllers()))) .Build() .Run(); } } public class HomeController : Controller { public HomeController(IStudentschool studentschool) => Debug.Assert(studentschool!= null); }
六、在Controller的Action方法中注入
借助于ASP.NET Core MVC基于模型绑定的参数绑定机制,我们可以将注册的服务绑定到目标Action方法的参数上,进而实现针对Action方法的依赖注入。
在采用这种类型的注入方式时,我们需要在注入参数上按照如下的方式标注FromServicesAttribute特性,用以确定参数绑定的来源是注册的服务。
在如下所示的代码片段
class Program { static void Main() { Host.CreateDefaultBuilder().ConfigureWebHostDefaults(builder => builder .ConfigureServices(svcs => svcs .AddSingleton<IStudentschool, Studentschool>() .AddControllersWithViews()) .Configure(app => app .UseRouting() .UseEndpoints(endpoints => endpoints.MapControllers()))) .Build() .Run(); } } public class HomeController: Controller { [HttpGet("/")] public void Index([FromServices]IStudentschool studentschool) { Debug.Assert(Studentschool!= null); } }
七、在视图中注入
在ASP.NET Core MVC应用中,我们还可以将服务注册到现的View中。
假设我们定义了如下这个简单的MVC程序,并定义了一个简单的HomeController。
如下代码片段
class Program { static void Main() { Host.CreateDefaultBuilder().ConfigureWebHostDefaults(builder => builder .ConfigureServices(svcs => svcs .AddSingleton<IStudentschool, Studentschool>() .AddControllersWithViews()) .Configure(app => app .UseRouting() .UseEndpoints(endpoints => endpoints.MapControllers()))) .Build() .Run(); } } public class HomeController: Controller { [HttpGet("/")] public IActionResult Index() => View(); }
我们为HomeController定义了一个路由指向根路径(“/”)的Action方法Index,该方法在调用View方法呈现默认的View之前,
将注入的IStudentschool服务以ViewBag的形式传递到View中。
如下所示的代码片段是这个Action方法对应View(/Views/Home/Index.cshtml)的定义,我们通过@inject指令注入了IStudentschool服务,并
将属性名设置为Studentschool,这意味着当前View对象将添加一个Studentschool属性来引用注入的服务。
@inject IStudentschool Studentschool @ { Debug.Assert(Studentschool!= null); }
写在后面
到这里就简单介绍了.NET Core依赖注入的使用方式,更多的使用方式还有待探索,一些使用过程当中的注意事项也需要探索,如:
- 有效地设计服务及其依赖关系;
- 防止多线程问题;
- 防止内存泄漏;
- 防止潜在的错误;
- 如果使用了服务注入,还要考虑服务生命周期(服务不能依赖于生命周期小于其自身的服务。);
参考: https://www.cnblogs.com/artech/p/di-in-asp-net-core-3.html