第十节:基于MVC5+Unity+EF+Log4Net的基础结构搭建

妖精的绣舞 提交于 2020-12-19 01:15:02

一. 前言

  本节继续探讨一种新的框架搭建模式,框架的结构划分和上一节是相同的,本节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.AdminWeb\bin\

  (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:\MyLog\OneLog\" />
 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:\MyLog\TwoLog\" />
 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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!