在netcore中实现字段和属性注入
简单来说,使用Ioc模式需要两个步骤,第一是把服务注册到容器中,第二是从容器中获取服务,我们一个一个讨论并演化。这里不会考虑使用如Autofac等第三方的容器来代替默认容器,只是提供一些简单实用的小方法用于简化应用层的开发。
将服务注入到容器
asp.netcore官方给出的在容器中注册服务方法是,要在Startup类的ConfigureServices方法中添加服务,如下所示:
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton(typeof(UserService));
    services.AddSingleton(typeof(MsgService));
    services.AddSingleton(typeof(OrderService));
}
AddMvc方法添加了mvc模块内部用到的一些服务,这个是封装好的,一句话就行了,其他第三方组件也都提供了类似的Add方法,把自己内部需要的服务都封装好注册进去了。但是我们应用开发人员使用的类,还是需要一个一个写进去的,大家最常见的三层架构中的数据访问层和业务逻辑层便是此类服务,上面代码中我加入了三个业务服务类。这显然不是长久之计,我想大家在开发中也会针对此问题做一些处理,这里说下我的,仅供参考吧。
解决方法就是批量注册!说到批量,就需要一个东西来标识一批东西,然后用这一个东西来控制这一批东西。在.net程序的世界中,有两个可选的角色,一个是接口Interface,另一个是特性Attribute。
如果使用接口作为标识来使用,限制就太死板了,一个标识的信息不是绝对的单一,是不推荐使用接口的,因为可能需要引入多个接口才能共同完成,所以我选择特性作为标识。特性相较与接口有什么特点呢?特性在运行时是类的实例,所以可以存储更多的信息。
下面我们简单实现一个AppServiceAttribute:
/// <summary>
/// 标记服务
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class AppServiceAttribute : Attribute
{
}
这个特性类取名AppService有两个理由,一是指定是应用层的服务类,二是避免使用Service这样的通用命名和其他类库冲突。
有了标识,就可以批量处理了,我们在一个新的类中给IServiceCollection提供一个扩展方法,用来批量添加标记有AppService特性的服务到容器中。
public static class AppServiceExtensions
{
    /// <summary>
    /// 注册应用程序域中所有有AppService特性的服务
    /// </summary>
    /// <param name="services"></param>
    public static void AddAppServices(this IServiceCollection services)
    {
        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            foreach (var type in assembly.GetTypes())
            {
                var serviceAttribute = type.GetCustomAttribute<AppServiceAttribute>();
                if (serviceAttribute != null)
                {
                    services.AddSingleton(type);
                }
            }
        }
    }
}
我们遍历应用程序中所有程序集,然后嵌套遍历每个程序集中的所有类型,判断类型是否有AppService特性,如果有的话就添加到容器中,这里有点不自信哦,为什么呢,因为我是使用AddSingleton方法以单例模式将服务添加到容器中的,虽然三层中的数据访问层和业务逻辑层绝大部分都可以使用单例,但是我们希望更通用一些,大家都知道netcore自带的Ioc容器支持三种生命周期,所以我们修改AppServiceAttribute,添加一个Lifetime属性:
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class AppServiceAttribute : Attribute
{
    /// <summary>
    /// 生命周期
    /// </summary>
    public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Singleton;
}
Lifetime的默认值我们设置成ServiceLifetime.Singleton是比较合适的,因为大部分服务我们都希望使用单例注册,一个合理的默认设置可以节省使用者很多代码,新手可能还会乐于复制粘贴,但老同志肯定都深有体会。
有了Lifetime这个信息,我们就可以改进AddAppServices方法了,在判断serviceAttribute不为null后,使用下面的代码替换services.AddSingleton(type):
    switch (serviceAttribute.Lifetime)
    {
        case ServiceLifetime.Singleton:
            services.AddSingleton(serviceType, type);
            break;
        case ServiceLifetime.Scoped:
            services.AddScoped(serviceType, type);
            break;
        case ServiceLifetime.Transient:
            services.AddTransient(serviceType, type);
            break;
        default:
            break;
    }
现在我们可以注册不同生命周期的服务了,只是该控制是在类的定义中,按理说,服务对象注册到容器中的生命周期,是不应该在类的定义中确定的,因为一个类的定义是独立的,定义好之后,使用者可以用任何一种容器支持的生命周期来注册实例。但是此时这样的设计是比较合理的,因为我们要解决的是应用层服务的批量注册,这类服务一般在定义的时候就已经确定了使用方式,而且很多时候服务的开发者就是该服务的使用者!所以我们可以把这个当成合理的反范式设计。
目前这样子,对于我来说,基本已经够用了,因为在应用层,我都是依赖实现编程的
在netcore中实现字段和属性注入的更多相关文章
- Netcore中实现字段和属性注入
		https://www.cnblogs.com/loogn/p/10566510.html 简单来说,使用Ioc模式需要两个步骤,第一是把服务注册到容器中,第二是从容器中获取服务,我们一个一个讨论并演 ... 
- C#中的字段与属性的区别及属性的作用
		C#中的字段与属性的区别及属性的作用 先上代码 public class Employee { //字段 private string name; //属性 public string Name { ... 
- C#类中的字段、属性和方法
		C#类中的字段.属性和方法 刚开始学C#,对于类中的字段.属性和方法很难分清,写下这份笔记,帮助理解 字段:与类相关的变量 声明方法与声明变量类似,可在前面添加访问修饰符.static关键字等: 属性 ... 
- ASP.NET Core中使用Autofac进行属性注入
		一些无关紧要的废话: 作为一名双修程序员(自封的),喜欢那种使用Spring的注解形式进行依赖注入或者Unity的特性形式进行依赖注入,当然,形式大同小异,但结果都是一样的,通过属性进行依赖注入. A ... 
- C#反射类中所有字段,属性,方法
		可能大家都知道在C#中如何创建一个类,但对于类的结构可能大家不一定了解的很清楚,对于我来说,我之前也搞的不是很明白,今天,当我没事研究反射的时候突然发现了着一点.我们来看类的结构到底是什么 publi ... 
- Java中的字段和属性
		Java中的属性,通常可以理解为get和set方法.而字段,通常叫做“类成员”. 属性只局限于类中方法的声明,并不与类中其他成员相关.例如:void setA(String s){}String ge ... 
- django中model字段与属性
		model field 类型1.AutoField 一个自增的IntegerField,一般不直接使用,Django会自动给每张表添加一个自增的primary key. 2.BigIntege ... 
- SQLSERVER获取数据库中的所有表的名称、表中所有字段的属性
		1.查询数据库中的所有数据库名: SELECT Name FROM Master..SysDatabases ORDER BY Name 2.查询某个数据库中所有的表名: SELECT Name FR ... 
- ms sql 根据表名查询 表中所有字段的属性值 sql语句
		SELECT表名=case when a.colorder=1 then d.name else '' end,--表说明=case when a.colorder=1 then isnull(f.v ... 
随机推荐
- Confluence 6 用户目录图例 - 只读连接 LDAP 整合本地用户组
			上面的图:Confluence 连接到一 LDAP 目录,权限对本地用户组设置为只读. https://www.cwiki.us/display/CONFLUENCEWIKI/Diagrams+of ... 
- mysql视图的作用
			测试表:user有id,name,age,sex字段 测试表:goods有id,name,price字段 测试表:ug有id,userid,goodsid字段 视图的作用实在是太强大了,以下是我体验过 ... 
- Android源码分析二 硬件抽象层(HAL)
			一 什么是HAL HAL 可定义一个标准接口以供硬件供应商实现,这可让 Android 忽略较低级别的驱动程序实现.借助 HAL,您可以顺利实现相关功能,而不会影响或更改更高级别的系统.HAL 实现会 ... 
- Python基础之函数二
			函数的嵌套 通过名字就能理解,函数里是还可以套着函数用的.这么牛,下面就来看看几段代码,看看是怎么回事.注意:函数一定是先定义后使用. x=1234 def f1(): #定义一个主函数 x = 1 ... 
- Jmeter 获取CSV行数
			import java.io.BufferedReader; import java.io.FileInputStream; String str = "E:\\Desktop\\WOS接口 ... 
- lsattr  chattr 文件安全设置
			[root@test_android_client_download xianlaigames]# lsattr -------------e- ./jilinmj.apk[root@test_and ... 
- PyCharm之python书写规范--消去提示波浪线
			强迫症患者面对PyCharm的波浪线是很难受的,针对如下代码去除PyCharm中的波浪线: # _*_coding:utf-8_*_ # /usr/bin/env python3 A_user = & ... 
- GreenDao3.2的简单使用
			Android -- GreenDao3.2的简单使用http://www.cnblogs.com/wjtaigwh/p/6394288.html https://github.com/greenro ... 
- 一个kubeadm.config文件--定义了token,扩展了默认端口,外部ETCD集群,自定义docker仓库,基于ipvs的kubeproxy
			这个版本是基于kubeadm.k8s.io/v1alpha3的,如果到了beta1,可能还要变动呢. apiVersion: kubeadm.k8s.io/v1alpha3 kind: InitCon ... 
- UE4 UPROPERTY UFUNCTION
			http://blog.csdn.net/sinat_27456831/article/details/52800514 
