从零开始,搭建博客系统MVC5+EF6搭建框架(3),添加Nlog日志、缓存机制(MemoryCache、RedisCache)、创建控制器父类BaseController

来源:互联网 发布:先知者软件怎么安装 编辑:程序博客网 时间:2024/05/29 02:09

一、回顾系统进度以及本章概要

     目前博客系统已经数据库创建、以及依赖注入Autofac集成,接下来就是日志和缓存集成,这里日志用的是Nlog,其实还有其他的日志框架如log4,这些博客园都有很多介绍,这里就不说了,缓存机制用的是微软自带的MemoryCache和比较流行Redis,这里我也只是了解使用,没有做更升入的研究,以后好好学一下Redis,然后就是实现一个BaseController父类用来重写JsonResult方法为的是返回时间格式问题,默认json返回的时间格式是Date(84923838332223)转为常见的yyyy-MM-dd HH:mm:ss格式。

二、缓存机制实现

1、在公共程序集中创建连个文件加一个Cache用来存放缓存类,一个是Log是用来创建Nlog类,这里都使用接口来实现,以便可以以后可以多个实现。

image

2、首先创建一个ICacheManager接口类。

  1 namespace Wchl.WMBlog.Common.Cache  2 {  3     public interface ICacheManager  4     {  5        /// <summary>  6        /// 获取  7        /// </summary>  8        /// <typeparam name="TEntity"></typeparam>  9        /// <param name="key"></param> 10        /// <returns></returns> 11         TEntity Get<TEntity>(string key); 12         //设置 13         void Set(string key, object value, TimeSpan cacheTime); 14         //判断是否存在 15         bool Contains(string key); 16         //移除 17         void Remove(string key); 18         //清除 19         void Clear(); 20  21     } 22 }
View Code

3、在实现微软缓存机制的时候需要引用System.Runtime.Caching.dll,创建一个MemoryCacheManager 类

  1 namespace Wchl.WMBlog.Common.Cache  2 {  3      public  class MemoryCacheManager : ICacheManager  4     {  5         public void Clear()  6         {  7   8             foreach (var item in MemoryCache.Default)  9             { 10                 this.Remove(item.Key); 11             } 12         } 13  14         public bool Contains(string key) 15         { 16             return MemoryCache.Default.Contains(key); 17         } 18  19         public TEntity Get<TEntity>(string key) 20         { 21             return (TEntity)MemoryCache.Default.Get(key); 22         } 23  24         public void Remove(string key) 25         { 26             MemoryCache.Default.Remove(key); 27         } 28  29         public void Set(string key, object value, TimeSpan cacheTime) 30         { 31             MemoryCache.Default.Add(key, value, new CacheItemPolicy { SlidingExpiration = cacheTime }); 32         } 33     } 34 }
View Code

4、实现RedisCacheManager类,这里我们使用的免费的Redis客服端是StackExchange.Redis.可以在nuget中下载到。

image

RedisCacheManager类

  1 namespace Wchl.WMBlog.Common.Cache  2 {  3     public class RedisCacheManager : ICacheManager  4     {  5         private readonly string redisConnenctionString;  6   7         public volatile ConnectionMultiplexer redisConnection;  8   9         private readonly object redisConnectionLock = new object(); 10  11         public RedisCacheManager() 12         { 13             //链接redis服务语句 14             string redisConfiguration = ConfigurationManager.ConnectionStrings["redisCache"].ToString(); 15  16             if (string.IsNullOrWhiteSpace(redisConfiguration)) 17             { 18                 throw new ArgumentException("redis config is empty", nameof(redisConfiguration)); 19             } 20             this.redisConnenctionString = redisConfiguration; 21             this.redisConnection = GetRedisConnection(); 22         } 23  24         private ConnectionMultiplexer GetRedisConnection() 25         { 26             if (this.redisConnection != null && this.redisConnection.IsConnected) 27             { 28                 return this.redisConnection; 29             } 30             lock (redisConnectionLock) 31             { 32                 if (this.redisConnection != null) 33                 { 34                     //释放redis连接 35                     this.redisConnection.Dispose(); 36                 } 37                 this.redisConnection = ConnectionMultiplexer.Connect(redisConnenctionString); 38             } 39             return this.redisConnection; 40         } 41  42         public void Clear() 43         { 44             foreach (var endPoint in this.GetRedisConnection().GetEndPoints()) 45             { 46                 var server = this.GetRedisConnection().GetServer(endPoint); 47                 foreach (var key in server.Keys()) 48                 { 49                     redisConnection.GetDatabase().KeyDelete(key); 50                 } 51             } 52         } 53  54         public bool Contains(string key) 55         { 56             return redisConnection.GetDatabase().KeyExists(key); 57         } 58  59         public TEntity Get<TEntity>(string key) 60         { 61             var value = redisConnection.GetDatabase().StringGet(key); 62             if (value.HasValue) 63             { 64                 return SerializeHelper.Deserialize<TEntity>(value); 65             } else 66             { 67                 return default(TEntity); 68             } 69         } 70  71         public void Remove(string key) 72         { 73             redisConnection.GetDatabase().KeyDelete(key); 74         } 75  76         public void Set(string key, object value, TimeSpan cacheTime) 77         { 78             if (value != null) 79             { 80                 redisConnection.GetDatabase().StringSet(key, SerializeHelper.Serialize(value), cacheTime); 81             } 82         } 83     } 84 }
View Code

这里在存储数据的时候使用到了序列化和反序列化,用的序列化工具是Newtonsoft.Json,同样也可以在nuget中找到。

image

SerializeHelper序列化帮助类

  1 namespace Wchl.WMBlog.Common  2 {  3     public class SerializeHelper  4     {  5         /// <summary>  6         /// 序列化  7         /// </summary>  8         /// <param name="item"></param>  9         /// <returns></returns> 10         public static byte[] Serialize(object item) 11         { 12             var jsonString = JsonConvert.SerializeObject(item); 13  14             return Encoding.UTF8.GetBytes(jsonString); 15         } 16         /// <summary> 17         /// 反序列化 18         /// </summary> 19         /// <typeparam name="TEntity"></typeparam> 20         /// <param name="value"></param> 21         /// <returns></returns> 22         public static TEntity Deserialize<TEntity>(byte[] value) 23         { 24             if (value == null) 25             { 26                 return default(TEntity); 27             } 28             var jsonString = Encoding.UTF8.GetString(value); 29             return JsonConvert.DeserializeObject<TEntity>(jsonString); 30         } 31     } 32 }
View Code

三、日志处理:Nlog日志框架

1、首先实现一个日子接口ILogger

  1 namespace Wchl.WMBlog.Common.Log  2 {  3     public interface ILogger  4     {  5         void Debug(string message);  6         void Debug(string message, Exception exception);  7         void Error(string message);  8         void Error(string message, Exception exception);  9         void Fatal(string message); 10         void Fatal(string message, Exception exception); 11         void Info(string message); 12         void Info(string message, Exception exception); 13         void Warn(string message); 14         void Warn(string message, Exception exception); 15     } 16 }
View Code

2.在nuget中添加Nlog框架

image

nlog.config是日志框架的配置文件。

Nloglogger类

  1 namespace Wchl.WMBlog.Common.Log  2 {  3     public class NLogLogger : ILogger  4     {  5         private readonly Logger logger = LogManager.GetCurrentClassLogger();  6         public void Debug(string message)  7         {  8             logger.Debug(message);  9         } 10  11         public void Debug(string message, Exception exception) 12         { 13             logger.Debug(exception, message); 14         } 15  16         public void Error(string message) 17         { 18             logger.Error(message); 19         } 20  21         public void Error(string message, Exception exception) 22         { 23             logger.Error(exception, message); 24         } 25  26         public void Fatal(string message) 27         { 28             logger.Fatal(message); 29         } 30  31         public void Fatal(string message, Exception exception) 32         { 33             logger.Fatal(exception, message); 34         } 35  36         public void Info(string message) 37         { 38             logger.Info(message); 39         } 40  41         public void Info(string message, Exception exception) 42         { 43             logger.Info(exception, message); 44         } 45  46         public void Warn(string message) 47         { 48             logger.Warn(message); 49         } 50  51         public void Warn(string message, Exception exception) 52         { 53             logger.Warn(exception, message); 54         } 55     } 56 }
View Code

3、配置日志文件NLog.config,这里是在webUI层应用这个文件,因为最终日志是在web下运行。

image

在targets的节点下面配置,这里是以文件的方式保存日子,你也可以使用这个配置一个直接把日子写到数据库中

  1 <target xsi:type ="File"  2     name="file"  3     header="------------------------------Start------------------------------"  4     footer="------------------------------End------------------------------"  5     fileName="${basedir}/App_Data/Logs/${shortdate}.log"  6     layout="${longdate} - ${level:uppercase=true}:${message} ${callsite:fileName=true} ${exception:format=Type,Message,Method,StackTrace:maxInnerExceptionLevel=5:innerFormat=ShortType,Message,Method,StackTrace}"  7     keepFileOpen="false"  8     archiveFileName="${basedir}/App_Data/Logs/Backup_${shortdate}.{##}.log"  9     archiveNumbering="Sequence" 10     archiveEvery="Day" 11     maxArchiveFiles="30"> 12  13     </target>
View Code

在rules节点下配置 <logger name="*" minlevel="Error" writeTo="file" />表示什么级别的日志对应放在哪个配置里面。

image

这里日志保存在发布站点App_Data\Logs下

image

4、日志测试

4.1在测试之前首先设置一个全局错误机制文件ExpFilter继承HandleErrorAttribute,放在Webcore下面

image

这里需要添加System.Web.Mvc.dll程序集。

ExpFilter类:

  1 namespace Wchl.WMBlog.WebCore  2 {  3     public class ExpFilter:HandleErrorAttribute  4     {  5         public override void OnException(ExceptionContext filterContext)  6         {  7             Exception exp = filterContext.Exception;  8   9             //获取ex的第一级内部异常 10             Exception innerEx = exp.InnerException == null ? exp : exp.InnerException; 11             //循环获取内部异常直到获取详细异常信息为止 12             while (innerEx.InnerException!=null) 13             { 14                 innerEx = innerEx.InnerException; 15             } 16             NLogLogger nlog = new NLogLogger(); 17             if (filterContext.HttpContext.Request.IsAjaxRequest()) 18             { 19  20                 nlog.Error(innerEx.Message); 21                 JsonConvert.SerializeObject(new { status = 1, msg ="请求发生错误,请联系管理员"}); 22             } 23             else 24             { 25                 nlog.Error("Error",exp); 26                 ViewResult vireResult = new ViewResult(); 27                 vireResult.ViewName = "/Views/Shared/Error.cshtml"; 28                 filterContext.Result = vireResult; 29             } 30  31             //告诉MVC框架异常被处理 32             filterContext.ExceptionHandled = true; 33             base.OnException(filterContext); 34         } 35     } 36 } 37 
View Code

4.2这里对两种请求方式做处理一种是Ajax请求,一种是对链接地址做处理,另外还需要在webui下创建一个错误提醒页面。(/Views/Shared/Error.cshtml)

image

4.3在homecontroller控制器下写错误代码

image

4.4日志测试结果:这里直接开始执行(不调试)

image

然后在项目文件下查看web站点下的\App_Data\Logs查看日子文件

image

日志信息:错误信息,以及错误是那个文件多少行都有显示。

image

四、创建BaseController类

这里使用反序列化工具都是Newtonsoft.Json

BaseController类:

  1 namespace Wchl.WMBlog.WebCore  2 {  3     public class BaseController: Controller  4     {  5         protected override JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)  6         {  7             return new JsonNetResult { Data = data, ContentType = contentType, ContentEncoding = contentEncoding, JsonRequestBehavior = behavior };  8         }  9     } 10 }
View Code

JsonNetResult类:

  1 namespace Wchl.WMBlog.WebCore  2 {  3     public class JsonNetResult:JsonResult  4     {  5         public override void ExecuteResult(ControllerContext context)  6         {  7             if (context==null)  8             {  9                 throw new ArgumentException(nameof(context)); 10             } 11  12             var response = context.HttpContext.Response; 13  14             response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/json"; 15  16             if (ContentEncoding != null) 17             { 18                 response.ContentEncoding = ContentEncoding; 19             } 20  21             var jsonSerializerSetting = new JsonSerializerSettings(); 22             //首字母小写 23             jsonSerializerSetting.ContractResolver = new CamelCasePropertyNamesContractResolver(); 24             //日期格式化 25             jsonSerializerSetting.DateFormatString = "yyyy-MM-dd HH:mm:ss"; 26             var json = JsonConvert.SerializeObject(Data, Formatting.None, jsonSerializerSetting); 27  28             response.Write(json); 29  30         } 31     } 32 }
View Code

直接在创建的控制器下集成:

image

   接下来就是准备实现页面布局,先做个简单的前台查看,后台分布的功能,然后在一步一步的完善,希望大家多多指点,多多支持,谢谢了。

    10月10日补充说明:

  全局错误处理机制需要在FilterConfig中配置,才能起作用。感谢园友1非烟的指正

image

0 0
原创粉丝点击