https://www.cnblogs.com/loogn/p/10566510.html

简单来说,使用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中实现字段和属性注入的更多相关文章

  1. 在netcore中实现字段和属性注入

    简单来说,使用Ioc模式需要两个步骤,第一是把服务注册到容器中,第二是从容器中获取服务,我们一个一个讨论并演化.这里不会考虑使用如Autofac等第三方的容器来代替默认容器,只是提供一些简单实用的小方 ...

  2. C#中的字段与属性的区别及属性的作用

    C#中的字段与属性的区别及属性的作用 先上代码 public class Employee { //字段 private string name; //属性 public string Name { ...

  3. C#类中的字段、属性和方法

    C#类中的字段.属性和方法 刚开始学C#,对于类中的字段.属性和方法很难分清,写下这份笔记,帮助理解 字段:与类相关的变量 声明方法与声明变量类似,可在前面添加访问修饰符.static关键字等: 属性 ...

  4. ASP.NET Core中使用Autofac进行属性注入

    一些无关紧要的废话: 作为一名双修程序员(自封的),喜欢那种使用Spring的注解形式进行依赖注入或者Unity的特性形式进行依赖注入,当然,形式大同小异,但结果都是一样的,通过属性进行依赖注入. A ...

  5. C#反射类中所有字段,属性,方法

    可能大家都知道在C#中如何创建一个类,但对于类的结构可能大家不一定了解的很清楚,对于我来说,我之前也搞的不是很明白,今天,当我没事研究反射的时候突然发现了着一点.我们来看类的结构到底是什么 publi ...

  6. Java中的字段和属性

    Java中的属性,通常可以理解为get和set方法.而字段,通常叫做“类成员”. 属性只局限于类中方法的声明,并不与类中其他成员相关.例如:void setA(String s){}String ge ...

  7. django中model字段与属性

    model field 类型1.AutoField     一个自增的IntegerField,一般不直接使用,Django会自动给每张表添加一个自增的primary key. 2.BigIntege ...

  8. SQLSERVER获取数据库中的所有表的名称、表中所有字段的属性

    1.查询数据库中的所有数据库名: SELECT Name FROM Master..SysDatabases ORDER BY Name 2.查询某个数据库中所有的表名: SELECT Name FR ...

  9. ms sql 根据表名查询 表中所有字段的属性值 sql语句

    SELECT表名=case when a.colorder=1 then d.name else '' end,--表说明=case when a.colorder=1 then isnull(f.v ...

随机推荐

  1. node Util 模块

    该util模块主要设计用于支持Node.js自己的内部API的需求.但是,许多实用程序对于应用程序和模块开发人员也很有用.它可以通过以下方式访问: const util = require('util ...

  2. 【摘自张宴的"实战:Nginx"】http auth baseic模块(打开页面需要密码验证)

    location /admin { auth_basic "kingsoft"; auth_basic_user_file httppasswd;      #密码文件的路径  默 ...

  3. Blender 基础 骨架 01

    Blender 基础 骨架 01 我使用的Blender版本:Blender V 2.77 前言 本讲介绍: 骨架的基本使用方式. 骨架是角色动画里面最常使用的元素,它可以准确控制一个模型的变形,尤其 ...

  4. 3DPDF是个什么东西?

    就是可以把3D模型放入到PDF中,然后客户可以直接用adobe reader查看这个PDF.经过搜索发现,大多数PDF编辑软件都没有直接把3D模型插入到PDF中的功能. 很多是3D软件自身提供的,比如 ...

  5. C++--VECTOR的简单应用

    在c++中,vector是一个十分有用的容器,下面对这个容器做一下总结. 1 基本操作 (1)头文件#include<vector>. (2)创建vector对象,vector<in ...

  6. RobotFramework教程使用笔记——robotframwork中文乱码显示问题

    转自:https://www.cnblogs.com/dreamyu/p/6878795.html 接口.数据库返回信息有中文的时候会显示unicode的样式,前面带个U这样的显示,如果我们想让它正常 ...

  7. Python-第三方库requests详解(附requests中文官方教程)

    转自http://blog.csdn.net/cyjs1988/article/details/73294774 Python+requests中文官方教程: http://www.python-re ...

  8. Altium Designer 3D模型的下载与添加

    先 先晒几个图:是不是很逼真啊..  ---------------------------------------教程---------------------------------------- ...

  9. angular 分页

    http://jsfiddle.net/SAWsA/11/# <html xmlns:ng="http://angularjs.org" ng-app lang=" ...

  10. centos7.4版本安装nmon监控软件

    一.检查安装环境 # uname –a (查看操作系统信息,所检查服务器为64位操作系统) Linux iZ94pmb2p24Z 2.6.32-431.23.3.el6.x86_64 #1 SMP T ...