专栏首页DotNet程序园Asp.NETCore让FromServices回来

Asp.NETCore让FromServices回来

起因

这两天,我忽然有点怀念 Asp.NET MVC 5 之前的时代,原因是我看到项目里面有这么一段代码(其实不止一段,几乎每个 Controller 都是)

    [Route("home")]    [ApiController]    public class HomeController : ControllerBase    {        private readonly IConfiguration configuration;        private readonly IHostingEnvironment environment;        private readonly CarService carService;        private readonly PostServices postServices;        private readonly TokenService tokenService;        private readonly TopicService topicService;        private readonly UserService userService;
        public HomeController(IConfiguration configuration,                              IHostingEnvironment environment,                              CarService carService,                              PostServices postServices,                              TokenService tokenService,                              TopicService topicService,                              UserService userService)        {            this.configuration = configuration;            this.environment = environment;            this.carService = carService;            this.postServices = postServices;            this.tokenService = tokenService;            this.topicService = topicService;            this.userService = userService;        }
        [HttpGet("index")]        public ActionResult<string> Index()        {            return "Hello world!";        }    }

在构造函数里面声明了一堆依赖注入的实例,外面还得声明相应的接收字段,使用代码克隆扫描,零零散散的充斥在各个 Controller 的构造函数中。在 Asp.NET MVC 5 之前,我们可以把上面的代码简化为下面的形式:

    [Route("home")]    [ApiController]    public class HomeController : ControllerBase    {        [FromServices] public IConfiguration Configuration { get; set; }        [FromServices] public IHostingEnvironment Environment { get; set; }        [FromServices] public CarService CarService { get; set; }        [FromServices] public PostServices PostServices { get; set; }        [FromServices] public TokenService TokenService { get; set; }        [FromServices] public TopicService TopicService { get; set; }        [FromServices] public UserService UserService { get; set; }
        public HomeController()        {        }
        [HttpGet("index")]        public ActionResult<string> Index()        {            return "Hello world!";        }    }

但是,在 .NETCore 中,上面的这断代码是会报错的,原因就是特性:FromServicesAttribute 只能应用于 AttributeTargets.Parameter,导航到 FromServicesAttribute 查看源码

namespace Microsoft.AspNetCore.Mvc{    /// <summary>    /// Specifies that an action parameter should be bound using the request services.    /// </summary>    /// <example>    /// In this example an implementation of IProductModelRequestService is registered as a service.    /// Then in the GetProduct action, the parameter is bound to an instance of IProductModelRequestService    /// which is resolved from the request services.    ///    /// <code>    /// [HttpGet]    /// public ProductModel GetProduct([FromServices] IProductModelRequestService productModelRequest)    /// {    ///     return productModelRequest.Value;    /// }    /// </code>    /// </example>    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]    public class FromServicesAttribute : Attribute, IBindingSourceMetadata    {        /// <inheritdoc />        public BindingSource BindingSource => BindingSource.Services;    }}

那么问题来了,AttributeUsage 是什么时候移除了 AttributeTargets.Property 呢?答案是:2015年11月17日,是一个叫做 Pranav K 的哥们革了 FromServiceAttribute 的命,下面是他的代码提交记录

Limit [FromServices] to apply only to parametershttps://github.com/aspnet/Mvc/commit/2a89caed05a1bc9f06d32e15d984cd21598ab6fb

这哥们的 Commit Message 很简洁:限制 FromServices 仅作用于 parameters 。高手过招,人狠话不多,刀刀致命!从此,广大 .NETCore 开发者告别了属性注入。经过我不懈努力的搜索后,发现其实在 Pranav K 提交代码两天后,他居然自己开了一个 Issue,你说气人不?

关于废除 FromServices 的讨论https://github.com/aspnet/Mvc/issues/3578

在这个贴子里面,许多开发者表达了自己的不满,我还看到了有人像我一样,表达了自己想要一个简洁的构造函数的这样朴素的请求;但是,对于属性注入可能导致滥用的问题也产生了激烈的讨论,还有属性注入要求成员必须标记为 public 这些硬性要求,不得不说,这个帖子成功的引起了人们的注意,但是很明显,作者不打算修改 FromServices 支持属性注入。

自己动手,丰衣足食

没关系,官方没有自带的话,我们自己动手做一个也是一样的效果,在此之前,我们还应该关注另外一种从 service 中获取实例的方式,就是常见的通过 HttpContext 请求上下文获取服务实例的方式:

 var obj = HttpContext.RequestServices.GetService(typeof(Type));

上面的这种方式,其实是反模式的,官方也建议尽量避免使用,说完了废话,就自动动手撸一个属性注入特性类:PropertyFromServiceAttribute

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]public class PropertyFromServiceAttribute : Attribute, IBindingSourceMetadata{    public BindingSource BindingSource => BindingSource.Services;}

没有多余的代码,就是标记为 AttributeTargets.Property 即可

应用到类成员
    [Route("home")]    [ApiController]    public class HomeController : ControllerBase    {        [PropertyFromService] public IConfiguration Configuration { get; set; }        [PropertyFromService] public IHostingEnvironment Environment { get; set; }        [PropertyFromService] public CarService CarService { get; set; }        [PropertyFromService] public PostServices PostServices { get; set; }        [PropertyFromService] public TokenService TokenService { get; set; }        [PropertyFromService] public TopicService TopicService { get; set; }        [PropertyFromService] public UserService UserService { get; set; }
        public HomeController()        {
        }
        [HttpGet("index")]        public ActionResult<string> Index()        {            return "Hello world!";        }    }

请大声的回答,上面的代码是不是非常的干净整洁!但是,像上面这样使用属性注入有一个小问题,在对象未初始化之前,该属性为 null,意味着在类的构造函数中,该成员变量不可用,不过不要紧,这点小问题完全可用通过在构造函数中注入解决;更重要的是,并非每个实例都需要在构造函数中使用,是吧。

示例代码

托管在 Github 上了 https://github.com/lianggx/Examples/tree/master/Ron.DI

** 如果你喜欢这篇文章,请给我点赞,让更多同学可以看到,笔芯~

本文分享自微信公众号 - DotNet程序园(dotnetblog),作者:梁规晓

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-06-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • FreeSql 新的八大骚功能

    FreeSql 目前版本号 0.5.5,预计明年元旦发布 1.0.0,切莫小看了版本号,目前单元测试方法1350+,并且每个方法内的涵盖面又比较广(不信的话见下...

    梁规晓
  • Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库

        在 .Net Core 2.2中 Microsoft.AspNetCore.App 默认内置了EntityFramework Core 包,所以在使用过...

    梁规晓
  • 什么样的代码是好代码?

    关于什么是好代码,软件行业烂大街的名词一大堆,什么高内聚、低耦合、可复用、可扩展、健壮性等等。也有所谓设计6原则—SOLID:

    梁规晓
  • Entity Framework复杂类型属性映射

    以上代码在ORM中称为组合类,EF会将这两个类映射在一张表中。当Code First发现不能推断出类的主键,并且没有通过Data Annotations或Flu...

    喵叔
  • ASP.NET.Core中使用AutoMapper

       接下来创建一个类来继承AutoMapper的Profile类与实现刚才创建的标志接口IProfile,并且在构造函数中配置关系映射

    莫问今朝
  • Entity Framework 小知识(五)

    在 多对多关系映射 中关联表是EF自动生成的。但有时候我们需要显示定义关联表。我们可以按照如下步骤定义(继续使用多对多关系映射这篇文章饿代码):

    喵叔
  • Entity Framework4.3 Code-First基于代码的数据迁移讲解1.建立一个最初的模型和数据库   2.启动Migration(数据迁移)3.第一个数据迁移4.订制的数据迁移4.动态

    前段时间一直在研究Entity Framework4,但是苦于没有找到我特别中意的教程,要么就是千篇一律的文章,而且写的特别简单,可以说,糟践了微软这么牛埃克斯...

    小白哥哥
  • 【C#】AutoMapper 使用手册

    官方文档:https://docs.automapper.org/en/latest/

    丹枫无迹
  • EF Code First 学习笔记:关系

    项目中最常用到的就是一对多关系了。Code First对一对多关系也有着很好的支持。很多情况下我们都不需要特意的去配置,Code First就能通过一些引用属性...

    跟着阿笨一起玩NET
  • Oracle中使用Entity Framework 6.x Code-First方式开发

    去年写过一篇EF的简单学习笔记,当时EF还不支持Oracle的Code-First开发模式,今天无意又看了下Oracle官网,发现EF6.X已经支持了,并且给出...

    菩提树下的杨过

扫码关注云+社区

领取腾讯云代金券