zoukankan      html  css  js  c++  java
  • 第十节:基于MVC5+Unity+EF+Log4Net的基础结构搭建

    一. 前言

      本节继续探讨一种新的框架搭建模式,框架的结构划分和上一节是相同的,本节IOC框架换成了Unity,并且采用构造函数注入的方式,另外服务层的封装模式也发生了变化,下面将详细的进行探讨。
    (一). 技术选型

      1. DotNet框架:4.6

      2. 数据库访问:EF 6.2 (CodeFrist模式)

      3. IOC框架:Unity 5.8.13

      4. 日志框架:log4net 2.0.8

      5. 开发工具:VS2017

    (二). 框架目标

      1. 一个项目同时连接多个相同种类的数据库,在一个方法中可以同时对多个数据进行操作。

      2. 支持多种数据库:SqlServer、MySQL、Oracle,灵活的切换数据库。

      3. 抽象成支持多种数据库连接方式:EF、ADO.Net、Dapper。

    二. 搭建思路

    1. 层次划分

      将框架分为:Ypf.Data、Ypf.IService、Ypf.Service、Ypf.DTO、Ypf.Utils、Ypf.AdminWeb 六个基本层(后续还会补充 Ypf.Api层),每层的作用分别为:

      ①. Ypf.Data:存放连接数据库的相关类,包括EF上下文类、映射的实体类、实体类的FluentApi模式的配置类。

      ②. Ypf.IService:业务接口层,用来约束接口规范。

      ③. Ypf.Service:业务层,用来编写整套项目的业务方法,但需要符合Ypf.IService层的接口约束。

      ④. Ypf.DTO: 存放项目中用到的自定义的实体类。

      ⑤. Ypf.Utils: 工具类

      ⑥. Ypf.AdminWeb: 表现层,系统的展示、接受用户的交互,传递数据,业务对接。

    PS:后续会补充Ypf.Api层,用于接受移动端、或其他客户端接口数据,进行相应的业务对接处理。

    2. Ypf.Data层的剖析

      EF封装到【Ypf.Data】层,通过Nuget引入EF的程序集,利用【来自数据库的code first】的模式先进行映射,后续通过DataAnnotations FluentAPI混合使用。该层结构如下:

    PS:EF的关闭默认策略、EF的DataAnnotations、EF的FluentAPI模式, 在关闭数据库策略的情况下,无论哪种模式都需要显式的 ToTable来映射表名,否则会提示该类找不到。

    EF配置详情参考:

             第十五节: EF的CodeFirst模式通过DataAnnotations修改默认协定

             第十六节: EF的CodeFirst模式通过Fluent API修改默认协定

    给【Ypf.AdminWeb】层,通过Nuget引入EF的程序集,并配置数据库连接字符串,直接在该层测试数据库访问。【测试通过】

    3. Service层和IService层简单的封装一下

      ①.【Ypf.Service】层只有一个BaseService普通类(非泛型)封装,【Ypf.IService】层有设置一个IBaseService接口,BaseService类实现IBaseService接口,里面的方法全部封装为泛型方法

      ②.【Ypf.Service】层中有很多自定义的 xxxService,每个xxxService都要实现【Ypf.IService】层的IxxxService层接口,同时继承BaseService类,这里的xxxService层划分并不依赖表名划分,自定义根据业务合理起名即可。

      ③. xxxService类中,在构造函数中传入DbContext db,但此处并不实例化,而是利用Unity进行构造函数的注入,所有的子类xxxService类中,都注入相应的EF上下文,这样就不需要手动再传入了(这里需要特别注意:Unity默认支持构造函数注入,只要xxxService被配置,那么该类中的(参数最多)的构造函数中的参数类即可以进行注入,只要在配置文件中配置上即可实现注入)。

      ④.在Unity的配置文件中进行配置IOC,在控制器中进行构造函数注入。

      ⑤ . 控制器中的Action仅仅负责传值和简单的一些判断,核心业务全部都写在Service层中。

      ⑥.  子类xxxService中的方法中,可以直接通过 this.XXX<T>的方式调用父类BaseService中的泛型方法,db是通过子类构造函数传到父类BaseService构造函数中。

    分享BaseService类和IBaseService接口:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Data.Entity;
      4 using System.Data.SqlClient;
      5 using System.Linq;
      6 using System.Linq.Expressions;
      7 using System.Reflection;
      8 using System.Text;
      9 using System.Threading.Tasks;
     10 using Ypf.IService;
     11 
     12 namespace Ypf.Service
     13 {
     14     public class BaseService: IBaseService
     15     {
     16         /// <summary>
     17         /// 一个属性,在该类中使用
     18         /// </summary>
     19         public DbContext db { get; private set; }
     20 
     21         /// <summary>
     22         /// 通过构造函数传入EF的上下文
     23         /// 该上下文可能是同种类型的不同数据库、也可能是相同结构的不同类型的数据库
     24         /// 为后面的Untiy的构造函数注入埋下伏笔
     25         /// </summary>
     26         /// <param name="db"></param>
     27         public BaseService(DbContext db)
     28         {
     29             this.db = db;
     30         }
     31 
     32 
     33         //1. 直接提交数据库
     34 
     35         #region 01-数据源
     36         public IQueryable<T> Entities<T>() where T : class
     37         {
     38             return db.Set<T>();
     39         }
     40 
     41         #endregion
     42 
     43         #region 02-新增
     44         public int Add<T>(T model) where T : class
     45         {
     46             DbSet<T> dst = db.Set<T>();
     47             dst.Add(model);
     48             return db.SaveChanges();
     49 
     50         }
     51         #endregion
     52 
     53         #region 03-删除(适用于先查询后删除 单个)
     54         /// <summary>
     55         /// 删除(适用于先查询后删除的单个实体)
     56         /// </summary>
     57         /// <param name="model">需要删除的实体</param>
     58         /// <returns></returns>
     59         public int Del<T>(T model) where T : class
     60         {
     61             db.Set<T>().Attach(model);
     62             db.Set<T>().Remove(model);
     63             return db.SaveChanges();
     64         }
     65         #endregion
     66 
     67         #region 04-根据条件删除(支持批量删除)
     68         /// <summary>
     69         /// 根据条件删除(支持批量删除)
     70         /// </summary>
     71         /// <param name="delWhere">传入Lambda表达式(生成表达式目录树)</param>
     72         /// <returns></returns>
     73         public int DelBy<T>(Expression<Func<T, bool>> delWhere) where T : class
     74         {
     75             List<T> listDels = db.Set<T>().Where(delWhere).ToList();
     76             listDels.ForEach(d =>
     77             {
     78                 db.Set<T>().Attach(d);
     79                 db.Set<T>().Remove(d);
     80             });
     81             return db.SaveChanges();
     82         }
     83         #endregion
     84 
     85         #region 05-单实体修改
     86         /// <summary>
     87         /// 修改
     88         /// </summary>
     89         /// <param name="model">修改后的实体</param>
     90         /// <returns></returns>
     91         public int Modify<T>(T model) where T : class
     92         {
     93             db.Entry(model).State = EntityState.Modified;
     94             return db.SaveChanges();
     95         }
     96         #endregion
     97 
     98         #region 06-批量修改(非lambda)
     99         /// <summary>
    100         /// 批量修改(非lambda)
    101         /// </summary>
    102         /// <param name="model">要修改实体中 修改后的属性 </param>
    103         /// <param name="whereLambda">查询实体的条件</param>
    104         /// <param name="proNames">lambda的形式表示要修改的实体属性名</param>
    105         /// <returns></returns>
    106         public int ModifyBy<T>(T model, Expression<Func<T, bool>> whereLambda, params string[] proNames) where T : class
    107         {
    108             List<T> listModifes = db.Set<T>().Where(whereLambda).ToList();
    109             Type t = typeof(T);
    110             List<PropertyInfo> proInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();
    111             Dictionary<string, PropertyInfo> dicPros = new Dictionary<string, PropertyInfo>();
    112             proInfos.ForEach(p =>
    113             {
    114                 if (proNames.Contains(p.Name))
    115                 {
    116                     dicPros.Add(p.Name, p);
    117                 }
    118             });
    119             foreach (string proName in proNames)
    120             {
    121                 if (dicPros.ContainsKey(proName))
    122                 {
    123                     PropertyInfo proInfo = dicPros[proName];
    124                     object newValue = proInfo.GetValue(model, null);
    125                     foreach (T m in listModifes)
    126                     {
    127                         proInfo.SetValue(m, newValue, null);
    128                     }
    129                 }
    130             }
    131             return db.SaveChanges();
    132         }
    133         #endregion
    134 
    135         #region 07-根据条件查询
    136         /// <summary>
    137         /// 根据条件查询
    138         /// </summary>
    139         /// <param name="whereLambda">查询条件(lambda表达式的形式生成表达式目录树)</param>
    140         /// <returns></returns>
    141         public List<T> GetListBy<T>(Expression<Func<T, bool>> whereLambda) where T : class
    142         {
    143             return db.Set<T>().Where(whereLambda).ToList();
    144         }
    145         #endregion
    146 
    147         #region 08-根据条件排序和查询
    148         /// <summary>
    149         /// 根据条件排序和查询
    150         /// </summary>
    151         /// <typeparam name="Tkey">排序字段类型</typeparam>
    152         /// <param name="whereLambda">查询条件</param>
    153         /// <param name="orderLambda">排序条件</param>
    154         /// <param name="isAsc">升序or降序</param>
    155         /// <returns></returns>
    156         public List<T> GetListBy<T,Tkey>(Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true) where T : class
    157         {
    158             List<T> list = null;
    159             if (isAsc)
    160             {
    161                 list = db.Set<T>().Where(whereLambda).OrderBy(orderLambda).ToList();
    162             }
    163             else
    164             {
    165                 list = db.Set<T>().Where(whereLambda).OrderByDescending(orderLambda).ToList();
    166             }
    167             return list;
    168         }
    169         #endregion
    170 
    171         #region 09-分页查询
    172         /// <summary>
    173         /// 根据条件排序和查询
    174         /// </summary>
    175         /// <typeparam name="Tkey">排序字段类型</typeparam>
    176         /// <param name="pageIndex">页码</param>
    177         /// <param name="pageSize">页容量</param>
    178         /// <param name="whereLambda">查询条件</param>
    179         /// <param name="orderLambda">排序条件</param>
    180         /// <param name="isAsc">升序or降序</param>
    181         /// <returns></returns>
    182         public List<T> GetPageList<T,Tkey>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true) where T : class
    183         {
    184 
    185             List<T> list = null;
    186             if (isAsc)
    187             {
    188                 list = db.Set<T>().Where(whereLambda).OrderBy(orderLambda)
    189                .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
    190             }
    191             else
    192             {
    193                 list = db.Set<T>().Where(whereLambda).OrderByDescending(orderLambda)
    194               .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
    195             }
    196             return list;
    197         }
    198         #endregion
    199 
    200         #region 10-分页查询输出总行数
    201         /// <summary>
    202         /// 根据条件排序和查询
    203         /// </summary>
    204         /// <typeparam name="Tkey">排序字段类型</typeparam>
    205         /// <param name="pageIndex">页码</param>
    206         /// <param name="pageSize">页容量</param>
    207         /// <param name="whereLambda">查询条件</param>
    208         /// <param name="orderLambda">排序条件</param>
    209         /// <param name="isAsc">升序or降序</param>
    210         /// <returns></returns>
    211         public List<T> GetPageList<T,Tkey>(int pageIndex, int pageSize, ref int rowCount, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true) where T : class
    212         {
    213             int count = 0;
    214             List<T> list = null;
    215             count = db.Set<T>().Where(whereLambda).Count();
    216             if (isAsc)
    217             {
    218                 var iQueryList = db.Set<T>().Where(whereLambda).OrderBy(orderLambda)
    219                    .Skip((pageIndex - 1) * pageSize).Take(pageSize);
    220 
    221                 list = iQueryList.ToList();
    222             }
    223             else
    224             {
    225                 var iQueryList = db.Set<T>().Where(whereLambda).OrderByDescending(orderLambda)
    226                  .Skip((pageIndex - 1) * pageSize).Take(pageSize);
    227                 list = iQueryList.ToList();
    228             }
    229             rowCount = count;
    230             return list;
    231         }
    232         #endregion
    233 
    234 
    235         //2. SaveChange剥离出来,处理事务
    236 
    237         #region 01-批量处理SaveChange()
    238         /// <summary>
    239         /// 事务批量处理
    240         /// </summary>
    241         /// <returns></returns>
    242         public int SaveChange()
    243         {
    244             return db.SaveChanges();
    245         }
    246         #endregion
    247 
    248         #region 02-新增
    249         /// <summary>
    250         /// 新增
    251         /// </summary>
    252         /// <param name="model">需要新增的实体</param>
    253         public void AddNo<T>(T model) where T : class
    254         {
    255             db.Set<T>().Add(model);
    256         }
    257         #endregion
    258 
    259         #region 03-删除
    260         /// <summary>
    261         /// 删除
    262         /// </summary>
    263         /// <param name="model">需要删除的实体</param>
    264         public void DelNo<T>(T model) where T : class
    265         {
    266             db.Entry(model).State = EntityState.Deleted;
    267         }
    268         #endregion
    269 
    270         #region 04-根据条件删除
    271         /// <summary>
    272         /// 条件删除
    273         /// </summary>
    274         /// <param name="delWhere">需要删除的条件</param>
    275         public void DelByNo<T>(Expression<Func<T, bool>> delWhere) where T : class
    276         {
    277             List<T> listDels = db.Set<T>().Where(delWhere).ToList();
    278             listDels.ForEach(d =>
    279             {
    280                 db.Set<T>().Attach(d);
    281                 db.Set<T>().Remove(d);
    282             });
    283         }
    284         #endregion
    285 
    286         #region 05-修改
    287         /// <summary>
    288         /// 修改
    289         /// </summary>
    290         /// <param name="model">修改后的实体</param>
    291         public void ModifyNo<T>(T model) where T : class
    292         {
    293             db.Entry(model).State = EntityState.Modified;
    294         }
    295         #endregion
    296 
    297 
    298         //3. EF调用sql语句
    299 
    300         #region 01-执行增加,删除,修改操作(或调用存储过程)
    301         /// <summary>
    302         /// 执行增加,删除,修改操作(或调用存储过程)
    303         /// </summary>
    304         /// <param name="sql"></param>
    305         /// <param name="pars"></param>
    306         /// <returns></returns>
    307         public int ExecuteSql(string sql, params SqlParameter[] pars)
    308         {
    309             return db.Database.ExecuteSqlCommand(sql, pars);
    310         }
    311 
    312         #endregion
    313 
    314         #region 02-执行查询操作
    315         /// <summary>
    316         /// 执行查询操作
    317         /// </summary>
    318         /// <typeparam name="T"></typeparam>
    319         /// <param name="sql"></param>
    320         /// <param name="pars"></param>
    321         /// <returns></returns>
    322         public List<T> ExecuteQuery<T>(string sql, params SqlParameter[] pars) where T : class
    323         {
    324             return db.Database.SqlQuery<T>(sql, pars).ToList();
    325         }
    326         #endregion
    327 
    328 
    329 
    330     }
    331 }
    BaseService类
      1 using System;
      2 using System.Collections.Generic;
      3 using System.Data.SqlClient;
      4 using System.Linq;
      5 using System.Linq.Expressions;
      6 using System.Text;
      7 using System.Threading.Tasks;
      8 
      9 namespace Ypf.IService
     10 {
     11     public interface IBaseService
     12     {
     13         //1. 直接提交数据库
     14 
     15         #region 01-数据源
     16         IQueryable<T> Entities<T>() where T : class;
     17 
     18         #endregion
     19 
     20         #region 02-新增
     21         int Add<T>(T model) where T : class;
     22 
     23         #endregion
     24 
     25         #region 03-删除(适用于先查询后删除 单个)
     26         /// <summary>
     27         /// 删除(适用于先查询后删除的单个实体)
     28         /// </summary>
     29         /// <param name="model">需要删除的实体</param>
     30         /// <returns></returns>
     31         int Del<T>(T model) where T : class;
     32 
     33         #endregion
     34 
     35         #region 04-根据条件删除(支持批量删除)
     36         /// <summary>
     37         /// 根据条件删除(支持批量删除)
     38         /// </summary>
     39         /// <param name="delWhere">传入Lambda表达式(生成表达式目录树)</param>
     40         /// <returns></returns>
     41         int DelBy<T>(Expression<Func<T, bool>> delWhere) where T : class;
     42 
     43         #endregion
     44 
     45         #region 05-单实体修改
     46         /// <summary>
     47         /// 修改
     48         /// </summary>
     49         /// <param name="model">修改后的实体</param>
     50         /// <returns></returns>
     51         int Modify<T>(T model) where T : class;
     52 
     53         #endregion
     54 
     55         #region 06-批量修改(非lambda)
     56         /// <summary>
     57         /// 批量修改(非lambda)
     58         /// </summary>
     59         /// <param name="model">要修改实体中 修改后的属性 </param>
     60         /// <param name="whereLambda">查询实体的条件</param>
     61         /// <param name="proNames">lambda的形式表示要修改的实体属性名</param>
     62         /// <returns></returns>
     63         int ModifyBy<T>(T model, Expression<Func<T, bool>> whereLambda, params string[] proNames) where T : class;
     64 
     65         #endregion
     66 
     67         #region 07-根据条件查询
     68         /// <summary>
     69         /// 根据条件查询
     70         /// </summary>
     71         /// <param name="whereLambda">查询条件(lambda表达式的形式生成表达式目录树)</param>
     72         /// <returns></returns>
     73         List<T> GetListBy<T>(Expression<Func<T, bool>> whereLambda) where T : class;
     74 
     75         #endregion
     76 
     77         #region 08-根据条件排序和查询
     78         /// <summary>
     79         /// 根据条件排序和查询
     80         /// </summary>
     81         /// <typeparam name="Tkey">排序字段类型</typeparam>
     82         /// <param name="whereLambda">查询条件</param>
     83         /// <param name="orderLambda">排序条件</param>
     84         /// <param name="isAsc">升序or降序</param>
     85         /// <returns></returns>
     86         List<T> GetListBy<T, Tkey>(Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true) where T : class;
     87 
     88         #endregion
     89 
     90         #region 09-分页查询
     91         /// <summary>
     92         /// 根据条件排序和查询
     93         /// </summary>
     94         /// <typeparam name="Tkey">排序字段类型</typeparam>
     95         /// <param name="pageIndex">页码</param>
     96         /// <param name="pageSize">页容量</param>
     97         /// <param name="whereLambda">查询条件</param>
     98         /// <param name="orderLambda">排序条件</param>
     99         /// <param name="isAsc">升序or降序</param>
    100         /// <returns></returns>
    101         List<T> GetPageList<T, Tkey>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true) where T : class;
    102 
    103         #endregion
    104 
    105         #region 10-分页查询输出总行数
    106         /// <summary>
    107         /// 根据条件排序和查询
    108         /// </summary>
    109         /// <typeparam name="Tkey">排序字段类型</typeparam>
    110         /// <param name="pageIndex">页码</param>
    111         /// <param name="pageSize">页容量</param>
    112         /// <param name="whereLambda">查询条件</param>
    113         /// <param name="orderLambda">排序条件</param>
    114         /// <param name="isAsc">升序or降序</param>
    115         /// <returns></returns>
    116         List<T> GetPageList<T, Tkey>(int pageIndex, int pageSize, ref int rowCount, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true) where T : class;
    117 
    118         #endregion
    119 
    120 
    121         //2. SaveChange剥离出来,处理事务
    122 
    123         #region 01-批量处理SaveChange()
    124         /// <summary>
    125         /// 事务批量处理
    126         /// </summary>
    127         /// <returns></returns>
    128         int SaveChange();
    129 
    130         #endregion
    131 
    132         #region 02-新增
    133         /// <summary>
    134         /// 新增
    135         /// </summary>
    136         /// <param name="model">需要新增的实体</param>
    137         void AddNo<T>(T model) where T : class;
    138 
    139         #endregion
    140 
    141         #region 03-删除
    142         /// <summary>
    143         /// 删除
    144         /// </summary>
    145         /// <param name="model">需要删除的实体</param>
    146         void DelNo<T>(T model) where T : class;
    147 
    148         #endregion
    149 
    150         #region 04-根据条件删除
    151         /// <summary>
    152         /// 条件删除
    153         /// </summary>
    154         /// <param name="delWhere">需要删除的条件</param>
    155         void DelByNo<T>(Expression<Func<T, bool>> delWhere) where T : class;
    156 
    157         #endregion
    158 
    159         #region 05-修改
    160         /// <summary>
    161         /// 修改
    162         /// </summary>
    163         /// <param name="model">修改后的实体</param>
    164         void ModifyNo<T>(T model) where T : class;
    165 
    166         #endregion
    167 
    168 
    169         //3. EF调用sql语句
    170 
    171         #region 01-执行增加,删除,修改操作(或调用存储过程)
    172         /// <summary>
    173         /// 执行增加,删除,修改操作(或调用存储过程)
    174         /// </summary>
    175         /// <param name="sql"></param>
    176         /// <param name="pars"></param>
    177         /// <returns></returns>
    178         int ExecuteSql(string sql, params SqlParameter[] pars);
    179 
    180         #endregion
    181 
    182         #region 02-执行查询操作
    183         /// <summary>
    184         /// 执行查询操作
    185         /// </summary>
    186         /// <typeparam name="T"></typeparam>
    187         /// <param name="sql"></param>
    188         /// <param name="pars"></param>
    189         /// <returns></returns>
    190         List<T> ExecuteQuery<T>(string sql, params SqlParameter[] pars) where T : class;
    191 
    192         #endregion
    193 
    194     }
    195 }
    IBaseService接口

    4. 利用Unity进行整合

      (1). 通过Nuget给【Ypf.Utils】层引入“Unity”的程序集和“Microsoft.AspNet.Mvc”程序集。

      (2). 新建类:DIFactory 用于读取Unity配置文件创建Unity容器。需要引入程序集“System.Configuration”

            新建类:UnityControllerFactory 用于自定义控制器实例化工厂。需要引入程序集“System.Web”。

    分享代码:

     1 using Microsoft.Practices.Unity;
     2 using Microsoft.Practices.Unity.Configuration;
     3 using System;
     4 using System.Collections.Generic;
     5 using System.Configuration;
     6 using System.IO;
     7 using System.Linq;
     8 using System.Text;
     9 using System.Threading.Tasks;
    10 using Unity;
    11 
    12 namespace Ypf.Utils
    13 {
    14     /// <summary>
    15     /// 依赖注入工厂(单例的 采用双if+lock锁)
    16     /// 读取Unity的配置文件,并创建Unity容器
    17     /// </summary>
    18     public class DIFactory
    19     {
    20         //静态的私有变量充当Lock锁
    21         private static object _lock = new object();
    22         private static Dictionary<string, IUnityContainer> _UnityDictory = new Dictionary<string, IUnityContainer>();
    23 
    24         /// <summary>
    25         /// 获取Unity容器
    26         /// </summary>
    27         /// <param name="containerName">对应配置文件中节点的名称,同时也当做字典中的key值</param>
    28         /// <returns></returns>
    29         public static IUnityContainer GetContainer(string containerName = "EFContainer")
    30         {
    31             if (!_UnityDictory.ContainsKey(containerName))
    32             {
    33                 lock (_lock)
    34                 {
    35                     if (!_UnityDictory.ContainsKey(containerName))
    36                     {
    37                         //1. 固定的4行代码读取配置文件
    38                         ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
    39                         fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\UnityConfig.xml");//找配置文件的路径
    40                         Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
    41                         UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
    42                         //2. Unity层次的步骤
    43                         IUnityContainer container = new UnityContainer();
    44                         section.Configure(container, containerName);
    45                         //3.将创建好的容器放到字典里
    46                         _UnityDictory.Add(containerName, container);
    47                     }
    48                 } 
    49             }
    50             return _UnityDictory[containerName];
    51         }
    52     }
    53 }
    DIFactory
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using System.Web.Mvc;
     7 using System.Web.Routing;
     8 using Unity;
     9 
    10 namespace Ypf.Utils
    11 {
    12     /// <summary>
    13     /// 自定义控制器实例化工厂
    14     /// </summary>
    15     public class UnityControllerFactory : DefaultControllerFactory
    16     {
    17         private IUnityContainer UnityContainer
    18         {
    19             get
    20             {
    21                 return DIFactory.GetContainer();
    22             }
    23         }
    24 
    25         /// <summary>
    26         /// 创建控制器对象
    27         /// </summary>
    28         /// <param name="requestContext"></param>
    29         /// <param name="controllerType"></param>
    30         /// <returns></returns>
    31         protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    32         {
    33             if (null == controllerType)
    34             {
    35                 return null;
    36             }
    37             IController controller = (IController)this.UnityContainer.Resolve(controllerType);
    38             return controller;
    39         }
    40 
    41         /// <summary>
    42         /// 释放控制器
    43         /// </summary>
    44         /// <param name="controller"></param>
    45         public override void ReleaseController(IController controller)
    46         {
    47             //this.UnityContainer.Teardown(controller);//释放对象(老版本)
    48 
    49             base.ReleaseController(controller);
    50         }
    51     }
    52 }
    UnityControllerFactory

      (3). 通过Nuget给【Ypf.AdminWeb】层引入“Unity”的程序集,并新建CfgFiles文件夹和UnityConfig.xml文件,该xml文件需要改属性为“始终复制”。

    分享代码:

     1 <configuration>
     2   <configSections>
     3     <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
     4   </configSections>
     5   <unity>
     6     <!-- unity容器配置注册节点-->
     7     <containers>      
     8       <!--容器配置方式一:类型名称和程序集名称全部写在容器中-->
     9       <container name="EFContainer">
    10         <!--  type中的两个参数分别是:类型名称和DLL程序集的名称 -->
    11         <!--  mapTo中的两个参数分别是:类型名称和DLL程序集的名称 -->
    12         <!--
    13           分析:这里我们需要使用的是TestService,但不直接使用它,而是使用它的接口,即将【mapTo】里的类型注册给【type】里的类型
    14         -->
    15         <register type="Ypf.IService.ITestService,Ypf.IService" mapTo="Ypf.Service.TestService,Ypf.Service"/>
    16         <register type="Ypf.IService.ITestService2,Ypf.IService" mapTo="Ypf.Service.TestService2,Ypf.Service"/>
    17         <!--调用构造函数注入-->
    18         <!--1.TestService需要依赖BaseService的构造函数,所以要对其进行注入-->
    19         <register type="Ypf.IService.IBaseService,Ypf.IService" mapTo="Ypf.Service.BaseService, Ypf.Service"/>
    20         <!--2.TestService需要传入EF的上下文,所以要对其进行注入-->
    21         <register type="System.Data.Entity.DbContext, EntityFramework" mapTo="Ypf.Data.MyDBContext1, Ypf.Data"  name="db"/>
    22         <register type="System.Data.Entity.DbContext, EntityFramework" mapTo="Ypf.Data.MyDBContext2, Ypf.Data"  name="db2"/>
    23 
    24       </container>
    25     </containers>
    26   </unity>
    27 </configuration>
    UnityConfig.xml

      (4). 将【Ypf.Service】层的程序集生成路径改为:..Ypf.AdminWebin

      (5). 在【Ypf.AdminWeb】层中的Global文件中进行注册 ,用Unity代替原有的控制器创建流程.

        //注册自定义实例化控制器的容器(利用Unity代替原有的控制器创建流程)

         ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory());

     PS:横向对比,AutoFac中也有一句类似的话:

      在【Ypf.AdminWeb】层测试Untiy的IOC和DI【测试通过】

    5. 将Log4net整合到Ypf.Utils层中。

      (1). 通过Nuget给【Ypf.Utils】层添加“Log4net”程序集。

      (2). 新建Log文件,拷贝“log4net.xml”和“LogUtils.cs”两个类文件,“log4net.xml”要改为嵌入的资源。

      (3). 在【Ypf.Admin】层的Global文件中进行注册。LogUtils.InitLog4Net();

      (4). 解析:主要配置了两种模式,输出到“txt文本文档”和“SQLServer数据库中”。其中“文本文档”又分了两种模式,全部输入到一个文档中 和 不同类型的日志输入到不同文档下,在调用的时候通过传入参数来区分存放在哪个文件夹下。

    代码详见下面的实战测试。

    6. 完善【Ypf.Service】层中BaseService的封装,封装EF常用的增删改查的方法,这里暂时先不扩展EF插件的方法。

    代码见上

    7.  如何控制EF上下文中的生命周期呢?

      在配置文件中可以通过lifetime这个节点进行配置,而上一套框架的模式是直接通过using的模式进行配置,这里可以使用默认的方式:每次使用时候都创建。

    详见Unity专题:

      Unity深入浅出(一)

      Unity深入浅出(二)

    三. 剖析核心

    1. 相同数据库结构,不同类型的数据库如何快速切换。

        解析:首先需要明白的是不同的数据库切换,实质上切换的就是 EF的上下文,该框架的模式EF的是使用Unity通过xxxService中子类的构造函数注入,需要在配置文件中配置构造函数注入EF上下文。

        <register type="System.Data.Entity.DbContext, EntityFramework" mapTo="Ypf.Data.MyDBContext1, Ypf.Data" />

     所以这里切换数据库(eg:SQLServer→MySQL)只需要通过Nuget引出EF对应数据库的程序集,编写好配置文件,将SQLServer的EF上下文(MyDbContext1)切换成MySQL的上下文即可。

    【需要测试】

    2. 在一个方法中如何同时访问多个数据库,并对其进行事务一体的增删改操作。

     解析:首先需要在BaseService的构造函数参数拼写多个DbContext参数,

     其次子类xxxService中同样也需要多个DbContext参数,当多个参数时候,需要通过命名的方式指定注入,否则相互覆盖,不能分别注入。

     

     最后,Unity的配置文件也需要通过命名的方式进行注入。

     

    思考,Dependency特性写在父类BaseService中是否可以?

    答案:经测试,不可以,EF的命名方式的构造函数注入要写在子类xxxService中。

    同时会带来一个弊端?

    由于BaseSevice类中泛型方法中的db,直接使用默认一个数据库的时候的db属性,所有导致当一个方法中如果涉及到多个上下文,没法直接使用BaseService中的封装方法,需要写原生代码,有点麻烦。

    如下图:

    那么如何解决这个问题?

    3. 连接多个数据库框架的局限性,如何改进。

      将BaseSevice中的泛型方法使用的db通过参数的形式进行传入,而且默认为一个数据库时候对应的DbContext属性,这样当只有一个数据库的时候,不用管它,因为他有默认值;当需要同时操控数据库的时候,在子类XXXService中,根据需要传入相应的db接口。

    【经测试,不可以,提示 默认参数必须是编译时候的常量】

     后续将采用别的方案进行处理,请期待。

    四. 实战测试

    这里准备两个数据库,分别是:YpfFrame_DB 和 YpfFrameTest_DB

    ①:YpfFrame_DB中,用到了表:T_SysUser 和 T_SysLoginLog,表结构如下

    ②. YpfFrameTest_DB 表中用到了T_SchoolInfor,表结构如下

    开始测试

    1. 测试增删改查,包括基本的事务一体。

    在【Ypf.IService】层中新建ITestService接口,在【Ypf.Service】层中新建TestService类,实现ITestService接口, 定义TestBasicCRUD方法,进行测试,代码如下。

     1          /// <summary>
     2         /// 1.测试基本的增删改查,事务一体
     3         /// </summary>
     4         /// <returns></returns>
     5         public int TestBasicCRUD()
     6         {
     7             //1.增加操作
     8             T_SysUser t_SysUser = new T_SysUser()
     9             {
    10                 id = Guid.NewGuid().ToString("N"),
    11                 userAccount = "123456",
    12                 userPwd = "XXX",
    13                 userRealName = "XXX",
    14                 appLoginNum = 1,
    15                 addTime = DateTime.Now
    16             };
    17             this.AddNo<T_SysUser>(t_SysUser);
    18 
    19             //2.修改操作
    20             T_SysLoginLog t_SysLoginLog = this.Entities<T_SysLoginLog>().Where(u => u.id == "1").FirstOrDefault();
    21             if (t_SysLoginLog != null)
    22             {
    23                 t_SysLoginLog.userId = "xxx";
    24                 t_SysLoginLog.userName = "xxx";
    25                 this.ModifyNo<T_SysLoginLog>(t_SysLoginLog);
    26             }
    27             //3.提交操作
    28             return db.SaveChanges();
    29         }

    2. 测试一个方法中查询多个数据库。

    在ITestService接口中定义ConnectManyDB方法,并在TestService中实现该方法,代码如下:

     

    3. 测试一个方法中事务一体处理多个数据库的crud操作。

     在ITestService接口中定义ManyDBTransaction方法,并在TestService中实现该方法,同样需要在构造函数中注入多个EF上下文,代码如下:

     1      [InjectionConstructor]
     2         public TestService([Dependency("db")]DbContext db, [Dependency("db2")]DbContext db2) : base(db, db2)
     3         {
     4 
     5         }
     6      /// <summary>
     7         /// 3. 同时对多个数据库进行事务一体的CRUD操作
     8         /// 注:需要手动开启msdtc服务(net start msdtc)
     9         /// </summary>
    10         public void ManyDBTransaction()
    11         {
    12             using (TransactionScope trans = new TransactionScope())
    13             {
    14                 try
    15                 {
    16                     var data1 = db.Set<T_SysUser>().Where(u => u.id == "1").FirstOrDefault();
    17                     if (data1 != null)
    18                     {
    19                         db.Set<T_SysUser>().Attach(data1);
    20                         db.Set<T_SysUser>().Remove(data1);
    21                         db.SaveChanges();
    22                     }
    23                     var data2 = db2.Set<T_SchoolInfor>().Where(u => u.id == "1").FirstOrDefault();
    24                     if (data2 != null)
    25                     {
    26                         db2.Set<T_SchoolInfor>().Attach(data2);
    27                         db2.Set<T_SchoolInfor>().Remove(data2);
    28                         db2.SaveChanges();
    29                     }
    30 
    31                     //最终提交事务
    32                     trans.Complete();
    33                 }
    34                 catch (Exception ex)
    35                 {
    36                     var msg = ex.Message;
    37                     //事务回滚
    38                     Transaction.Current.Rollback();
    39                     throw;
    40                 }
    41             }
    42         }

      分析:同时连接多个数据库,并对多个数据库进行事务性的crud操作,这个时候必须用 【TransactionScope事务】需要引入System.Transactions程序集,前提要手动 【net start msdtc 】开启对应服务,这样整个事务通过“Complete”方法进行提交,通过Transaction.Current.Rollback()方法进行事务回滚,各自db的SaveChange不起作用,但还是需要SaveChange的。

    4. 测试xxxSevice子类中也可以通过Unity进行IxxxService的属性模式进行属性的注入。

    PS:为了与前一节中AutoFac相呼应

     在【Ypf.IService】层中新建ITestService2接口,在【Ypf.Service】层中新建TestService2类,实现ITestService接口, 定义GetUserInfor方法,进行测试,代码如下。

     1  public class TestService2 : BaseService, ITestService2
     2     {
     3         /// <summary>
     4         /// 调用父类的构造函数,这里的db通过Unity的配置文件实现构造函数注入
     5         /// </summary>
     6         /// <param name="db"></param>
     7         [InjectionConstructor]
     8         public TestService2([Dependency("db")]DbContext db, [Dependency("db2")]DbContext db2) : base(db, db2)
     9         {
    10 
    11         }
    12 
    13         public List<T_SysUser> GetUserInfor()
    14         {
    15             return this.GetListBy<T_SysUser>(u => true);
    16         }
    17     }
    View Code

    在TestService中定义ITestService2属性,如下:

     

    在TestService中定义如下方法,内部用TestService2进行调用,可以调用成功,从而证明xxxSevice子类中也可以通过Unity进行IxxxService的模式进行“属性的注入”。

     

    5. 测试Log4net的分文件夹和不分文件的使用。

    分享配置文件

      1 <?xml version="1.0" encoding="utf-8" ?>
      2 <configuration>
      3   <!-- 一. 添加log4net的自定义配置节点-->
      4   <configSections>
      5     <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
      6   </configSections>
      7   <!--二. log4net的核心配置代码-->
      8   <log4net>
      9     <!--1. 输出途径(一) 将日志以回滚文件的形式写到文件中-->
     10     
     11     <!--模式一:全部存放到一个文件夹里-->
     12     <appender name="log0" type="log4net.Appender.RollingFileAppender">
     13       <!--1.1 文件夹的位置(也可以写相对路径)-->
     14       <param name="File"  value="D:MyLog" />
     15       <!--相对路径-->
     16       <!--<param name="File"  value="Logs/" />-->
     17       <!--1.2 是否追加到文件-->
     18       <param name="AppendToFile" value="true" />
     19       <!--1.3 使用最小锁定模型(minimal locking model),以允许多个进程可以写入同一个文件 -->
     20       <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
     21       <!--1.4 配置Unicode编码-->
     22       <Encoding value="UTF-8" />
     23       <!--1.5 是否只写到一个文件里-->
     24       <param name="StaticLogFileName" value="false" />
     25       <!--1.6 配置按照何种方式产生多个日志文件 (Date:日期、Size:文件大小、Composite:日期和文件大小的混合方式)-->
     26       <param name="RollingStyle" value="Composite" />
     27       <!--1.7 介绍多种日志的的命名和存放在磁盘的形式-->
     28       <!--1.7.1 在根目录下直接以日期命名txt文件 注意&quot;的位置,去空格 -->
     29       <param name="DatePattern" value="yyyy-MM-dd&quot;.log&quot;" />
     30       <!--1.7.2 在根目录下按日期产生文件夹,文件名固定 test.log  -->
     31       <!--<param name="DatePattern" value="yyyy-MM-dd/&quot;test.log&quot;"  />-->
     32       <!--1.7.3 在根目录下按日期产生文件夹,这是按日期产生文件夹,并在文件名前也加上日期  -->
     33       <!--<param name="DatePattern" value="yyyyMMdd/yyyyMMdd&quot;-test.log&quot;"  />-->
     34       <!--1.7.4 在根目录下按日期产生文件夹,这再形成下一级固定的文件夹  -->
     35       <!--<param name="DatePattern" value="yyyyMMdd/&quot;OrderInfor/test.log&quot;"  />-->
     36       <!--1.8 配置每个日志的大小。【只在1.6 RollingStyle 选择混合方式与文件大小方式下才起作用!!!】可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志,
     37       超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。-->
     38       <param name="maximumFileSize" value="10MB" />
     39       <!--1.9 最多产生的日志文件个数,超过则保留最新的n个 将value的值设置-1,则不限文件个数 【只在1.6 RollingStyle 选择混合方式与文件大小方式下才起作用!!!】
     40         与1.8中maximumFileSize文件大小是配合使用的-->
     41       <param name="MaxSizeRollBackups" value="5" />
     42       <!--1.10 配置文件文件的布局格式,使用PatternLayout,自定义布局-->
     43       <layout type="log4net.Layout.PatternLayout">
     44         <conversionPattern value="记录时间:%date %n线程ID:[%thread] %n日志级别:%-5level %n出错类:%logger property: [%property{NDC}] - %n错误描述:%message%newline %n%newline"/>
     45       </layout>
     46     </appender>
     47 
     48     <!--模式二:分文件夹存放-->
     49     <!--文件夹1-->
     50     <appender name="log1" type="log4net.Appender.RollingFileAppender">
     51       <param name="File"  value="D:MyLogOneLog" />
     52       <param name="AppendToFile" value="true" />
     53       <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
     54       <Encoding value="UTF-8" />
     55       <param name="StaticLogFileName" value="false" />
     56       <param name="RollingStyle" value="Composite" />
     57       <param name="DatePattern" value="yyyy-MM-dd&quot;.log&quot;" />
     58       <param name="maximumFileSize" value="10MB" />
     59       <param name="MaxSizeRollBackups" value="5" />
     60       <layout type="log4net.Layout.PatternLayout">
     61         <conversionPattern value="%message%newline" />
     62       </layout>
     63       <!--下面是利用过滤器进行分文件夹存放,两种过滤器进行配合-->
     64       <!--与Logger名称(OneLog)匹配,才记录,-->
     65       <filter type="log4net.Filter.LoggerMatchFilter">
     66         <loggerToMatch value="OneLog" />
     67       </filter>
     68       <!--阻止所有的日志事件被记录-->
     69       <filter type="log4net.Filter.DenyAllFilter" />
     70     </appender>
     71     <!--文件夹2-->
     72     <appender name="log2" type="log4net.Appender.RollingFileAppender">
     73       <param name="File"  value="D:MyLogTwoLog" />
     74       <param name="AppendToFile" value="true" />
     75       <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
     76       <Encoding value="UTF-8" />
     77       <param name="StaticLogFileName" value="false" />
     78       <param name="RollingStyle" value="Composite" />
     79       <param name="DatePattern" value="yyyy-MM-dd&quot;.log&quot;" />
     80       <param name="maximumFileSize" value="10MB" />
     81       <param name="MaxSizeRollBackups" value="5" />
     82       <layout type="log4net.Layout.PatternLayout">
     83         <conversionPattern value="%message%newline" />
     84       </layout>
     85       <!--下面是利用过滤器进行分文件夹存放,两种过滤器进行配合-->
     86       <!--与Logger名称(TwoLog)匹配,才记录,-->
     87       <filter type="log4net.Filter.LoggerMatchFilter">
     88         <loggerToMatch value="TwoLog" />
     89       </filter>
     90       <!--阻止所有的日志事件被记录-->
     91       <filter type="log4net.Filter.DenyAllFilter" />
     92     </appender>
     93 
     94 
     95     <!--2. 输出途径(二) 记录日志到数据库-->
     96     <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
     97       <!--2.1 设置缓冲区大小,只有日志记录超设定值才会一块写入到数据库-->
     98       <param name="BufferSize" value="1" />
     99       <!--2.2 引用-->
    100       <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    101       <!--2.3 数据库连接字符串-->
    102       <connectionString value="data source=localhost;initial catalog=LogDB;integrated security=false;persist security info=True;User ID=sa;Password=123456" />
    103       <!--2.4 SQL语句插入到指定表-->
    104       <commandText value="INSERT INTO LogInfor ([threadId],[log_level],[log_name],[log_msg],[log_exception],[log_time]) VALUES (@threadId, @log_level, @log_name, @log_msg, @log_exception,@log_time)" />
    105       <!--2.5 数据库字段匹配-->
    106       <!-- 线程号-->
    107       <parameter>
    108         <parameterName value="@threadId" />
    109         <dbType value="String" />
    110         <size value="100" />
    111         <layout type="log4net.Layout.PatternLayout">
    112           <conversionPattern value="%thread" />
    113         </layout>
    114       </parameter>
    115       <!--日志级别-->
    116       <parameter>
    117         <parameterName value="@log_level" />
    118         <dbType value="String" />
    119         <size value="100" />
    120         <layout type="log4net.Layout.PatternLayout">
    121           <conversionPattern value="%level" />
    122         </layout>
    123       </parameter>
    124       <!--日志记录类名称-->
    125       <parameter>
    126         <parameterName value="@log_name" />
    127         <dbType value="String" />
    128         <size value="100" />
    129         <layout type="log4net.Layout.PatternLayout">
    130           <conversionPattern value="%logger" />
    131         </layout>
    132       </parameter>
    133       <!--日志信息-->
    134       <parameter>
    135         <parameterName value="@log_msg" />
    136         <dbType value="String" />
    137         <size value="5000" />
    138         <layout type="log4net.Layout.PatternLayout">
    139           <conversionPattern value="%message" />
    140         </layout>
    141       </parameter>
    142       <!--异常信息  指的是如Infor 方法的第二个参数的值-->
    143       <parameter>
    144         <parameterName value="@log_exception" />
    145         <dbType value="String" />
    146         <size value="2000" />
    147         <layout type="log4net.Layout.ExceptionLayout" />
    148       </parameter>
    149       <!-- 日志记录时间-->
    150       <parameter>
    151         <parameterName value="@log_time" />
    152         <dbType value="DateTime" />
    153         <layout type="log4net.Layout.RawTimeStampLayout" />
    154       </parameter>
    155     </appender>
    156 
    157 
    158     <!--(二). 配置日志的的输出级别和加载日志的输出途径-->
    159     <root>
    160       <!--1. level中的value值表示该值及其以上的日志级别才会输出-->
    161       <!--OFF > FATAL(致命错误) > ERROR(一般错误) > WARN(警告) > INFO(一般信息) > DEBUG(调试信息)  > ALL  -->
    162       <!--OFF表示所有信息都不写入,ALL表示所有信息都写入-->
    163       <level value="ALL"></level>
    164       <!--2. append-ref标签表示要加载前面的日志输出途径代码  通过ref和appender标签的中name属性相关联-->
    165       
    166       <appender-ref ref="log0"></appender-ref>
    167       <appender-ref ref="log1"></appender-ref>
    168       <appender-ref ref="log2"></appender-ref>
    169 
    170       <!--<appender-ref ref="AdoNetAppender"></appender-ref>-->
    171     </root>
    172   </log4net>
    173 
    174 </configuration>
    View Code

    分享对应帮助类封装

      1 using log4net;
      2 using System;
      3 using System.Collections.Generic;
      4 using System.Diagnostics;
      5 using System.Linq;
      6 using System.Reflection;
      7 using System.Text;
      8 using System.Threading.Tasks;
      9 
     10 namespace Ypf.Utils.Log
     11 {
     12     public class LogUtils
     13     {
     14         //声明文件夹名称(这里分两个文件夹)
     15         static string log1Name = "OneLog";
     16         static string log2Name = "TwoLog";
     17 
     18         //可以声明多个日志对象
     19         //模式一:不分文件夹(所有的log对存放在这一个文件夹下)
     20         public static ILog log = LogManager.GetLogger(typeof(LogUtils));
     21 
     22         //模式二:分文件夹
     23         //如果是要分文件夹存储,这里的名称需要和配置文件中loggerToMatch节点中的value相配合
     24         //1. OneLog文件夹
     25         public static ILog log1 = LogManager.GetLogger(log1Name);
     26         //2. TwoLog文件夹
     27         public static ILog log2 = LogManager.GetLogger(log2Name);
     28 
     29         #region 01-初始化Log4net的配置
     30         /// <summary>
     31         /// 初始化Log4net的配置
     32         /// xml文件一定要改为嵌入的资源
     33         /// </summary>
     34         public static void InitLog4Net()
     35         {
     36             Assembly assembly = Assembly.GetExecutingAssembly();
     37             var xml = assembly.GetManifestResourceStream("Ypf.Utils.Log.log4net.xml");
     38             log4net.Config.XmlConfigurator.Configure(xml);
     39         }
     40         #endregion
     41 
     42         /************************* 五种不同日志级别 *******************************/
     43         //FATAL(致命错误) > ERROR(一般错误) > WARN(警告) > INFO(一般信息) > DEBUG(调试信息)
     44 
     45         #region 00-将调试的信息输出,可以定位到具体的位置(解决高层封装带来的问题)
     46         /// <summary>
     47         /// 将调试的信息输出,可以定位到具体的位置(解决高层封装带来的问题)
     48         /// </summary>
     49         /// <returns></returns>
     50         private static string getDebugInfo()
     51         {
     52             StackTrace trace = new StackTrace(true);
     53             return trace.ToString();
     54         }
     55         #endregion
     56 
     57         #region 01-DEBUG(调试信息)
     58         /// <summary>
     59         /// DEBUG(调试信息)
     60         /// </summary>
     61         /// <param name="msg">日志信息</param>
     62         ///  <param name="logName">文件夹名称</param>
     63         public static void Debug(string msg, string logName = "")
     64         {
     65             if (logName == "")
     66             {
     67                 log.Debug(getDebugInfo() + msg);
     68             }
     69             else if (logName == log1Name)
     70             {
     71                 log1.Debug(msg);
     72             }
     73             else if (logName == log2Name)
     74             {
     75                 log2.Debug(msg);
     76             }
     77         }
     78         /// <summary>
     79         /// Debug
     80         /// </summary>
     81         /// <param name="msg">日志信息</param>
     82         /// <param name="exception">错误信息</param>
     83         public static void Debug(string msg, Exception exception)
     84         {
     85             log.Debug(getDebugInfo() + msg, exception);
     86         }
     87 
     88         #endregion
     89 
     90         #region 02-INFO(一般信息)
     91         /// <summary>
     92         /// INFO(一般信息)
     93         /// </summary>
     94         /// <param name="msg">日志信息</param>
     95         /// <param name="logName">文件夹名称</param>
     96         public static void Info(string msg, string logName = "")
     97         {
     98             if (logName == "")
     99             {
    100                 log.Info(getDebugInfo() + msg);
    101             }
    102             else if (logName == log1Name)
    103             {
    104                 log1.Info(msg);
    105             }
    106             else if (logName == log2Name)
    107             {
    108                 log2.Info(msg);
    109             }
    110         }
    111         /// <summary>
    112         /// Info
    113         /// </summary>
    114         /// <param name="msg">日志信息</param>
    115         /// <param name="exception">错误信息</param>
    116         public static void Info(string msg, Exception exception)
    117         {
    118             log.Info(getDebugInfo() + msg, exception);
    119         }
    120         #endregion
    121 
    122         #region 03-WARN(警告)
    123         /// <summary>
    124         ///WARN(警告)
    125         /// </summary>
    126         /// <param name="msg">日志信息</param>
    127         /// <param name="logName">文件夹名称</param>
    128         public static void Warn(string msg, string logName = "")
    129         {
    130             if (logName == "")
    131             {
    132                 log.Warn(getDebugInfo() + msg);
    133             }
    134             else if (logName == log1Name)
    135             {
    136                 log1.Warn(msg);
    137             }
    138             else if (logName == log2Name)
    139             {
    140                 log2.Warn(msg);
    141             }
    142         }
    143         /// <summary>
    144         /// Warn
    145         /// </summary>
    146         /// <param name="msg">日志信息</param>
    147         /// <param name="exception">错误信息</param>
    148         public static void Warn(string msg, Exception exception)
    149         {
    150             log.Warn(getDebugInfo() + msg, exception);
    151         }
    152         #endregion
    153 
    154         #region 04-ERROR(一般错误)
    155         /// <summary>
    156         /// ERROR(一般错误)
    157         /// </summary>
    158         /// <param name="msg">日志信息</param>
    159         /// <param name="logName">文件夹名称</param>
    160         public static void Error(string msg, string logName = "")
    161         {
    162             if (logName == "")
    163             {
    164                 log.Error(getDebugInfo() + msg);
    165             }
    166             else if (logName == log1Name)
    167             {
    168                 log1.Error(msg);
    169             }
    170             else if (logName == log2Name)
    171             {
    172                 log2.Error(msg);
    173             }
    174         }
    175         /// <summary>
    176         /// Error
    177         /// </summary>
    178         /// <param name="msg">日志信息</param>
    179         /// <param name="exception">错误信息</param>
    180         public static void Error(string msg, Exception exception)
    181         {
    182             log.Error(getDebugInfo() + msg, exception);
    183         }
    184         #endregion
    185 
    186         #region 05-FATAL(致命错误)
    187         /// <summary>
    188         /// FATAL(致命错误)
    189         /// </summary>
    190         /// <param name="msg">日志信息</param>
    191         /// <param name="logName">文件夹名称</param>
    192         public static void Fatal(string msg, string logName = "")
    193         {
    194             if (logName == "")
    195             {
    196                 log.Fatal(getDebugInfo() + msg);
    197             }
    198             else if (logName == log1Name)
    199             {
    200                 log1.Fatal(msg);
    201             }
    202             else if (logName == log2Name)
    203             {
    204                 log2.Fatal(msg);
    205             }
    206         }
    207         /// <summary>
    208         /// Fatal
    209         /// </summary>
    210         /// <param name="msg">日志信息</param>
    211         /// <param name="exception">错误信息</param>
    212         public static void Fatal(string msg, Exception exception)
    213         {
    214             log.Fatal(getDebugInfo() + msg, exception);
    215         }
    216 
    217         #endregion
    218 
    219 
    220 
    221     }
    222 }
    View Code

    代码测试

    五. 后续

      后续将对比 Unity和AutoFac,对比这两套框架的搭建模式。

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
  • 相关阅读:
    每日日报
    每日日报
    flink入门到实战(2)flink优化总结
    flink入门到实战(1)入门学习
    机器学习算法一般步骤
    hadoop入门到实战(1)hive优化总结
    划重点|iOS15正式发布, 全新的通知推送系统,你必须要知道!
    云知声 Atlas 超算平台: 基于 Fluid + Alluxio 的计算加速实践
    终端卡顿优化的全记录
    云湖共生释放企业数据价值
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/9986930.html
Copyright © 2011-2022 走看看