当前位置: 移动技术网 > IT编程>开发语言>.net > Asp.NETCore让FromServices回来

Asp.NETCore让FromServices回来

2019年06月26日  | 移动技术网IT编程  | 我要评论
我有一个朴素的请求:我想在 .NETCore 中使用属性注入,我想要 FromServiceAttrbute 在属性上注入的功能。 ...

起因

这两天,我忽然有点怀念 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 parameters
https://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

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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网