在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 ...
随机推荐
- Pod 找不到头文件 解决方法
在 BuildSetting 中 搜索 User Header Search Paths 然后在下面 User Header Search Paths 中添加 ${SRCROOT} 再将后面参数改为 ...
- 【Java】「深入理解Java虚拟机」学习笔记(4)- 类文件结构
我为什么喜欢Java,另一个重要原因就是跨平台,WORA. 程序员是爽了,但肯定有人要为你遮风挡雨,解决WORA的基石就是字节码+虚拟机. ♣Tip 其实这里存在两种无关性,一是平台无关性.另一个是语 ...
- python并发编程之多进程1-----------互斥锁与进程间的通信
一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...
- css样式之补充。。。
css常用的一些属性: 1.去掉下划线 :text-decoration:none ;2.加上下划线: text-decoration: underline; 3.调整文本和图片的位置(也就是设置元素 ...
- 数据恢复Winhex的核心理念
一.数据恢复就是寻找有价值的东西,其本质是数据定位,检索技术.存在的有迹可循,毁灭的无影无踪.这就譬如说,一本撕烂的书输的目录不见了,但是内容全在,我们就可以读到内容,但是内容不存在了,也就无法在找到 ...
- java----DOS命令
dir /? 查看帮助 dir /s 查看当前的目录,以及子目录
- hdu5015构造转移矩阵
/* 构造转移矩阵: 先推公式: 首先是第0行:A[0][j+1]=A[0][j]*10+3 1-n行: A[i][j+1]=A[i][j]+A[i-1][j+1]=... =A[i][j]+A[i- ...
- hdu1565 用搜索代替枚举找可能状态或者轮廓线解(较优),参考poj2411
这题用直接枚举是超时的,必须要用搜索来搜索出所有可能的状态,然后再进行枚举 这是较慢的做法 /* 方格取数,相邻格子的数不可取,问最多取到的和是什么 有点类似炮兵布阵,先打出所有可能的状态,然后dp[ ...
- Datagrip导入导出为一个sql文件详细说明 (mysql)
Datagrip导入导出为一个sql文件详细说明 导出: (我的无法截图, 借用一张) 导入: (我的无法截图, 再借用一张) 完
- SSM + Android 网络文件上传下载
SSM + Android 网络交互的那些事 2016年12月14日 17:58:36 ssm做为后台与android交互,相信只要是了解过的人都知道一些基本的数据交互,向json,对象,map的交互 ...