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


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

         目前博客系统已经数据库创建、以及依赖注入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_DataLogs下

    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_DataLogs查看日子文件

    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

  • 相关阅读:
    上一张作业day16
    python 函数递归,三元表达式解读,匿名一次性函数,模块略解
    迭代器,生成器与内置函数
    闭合函数和装饰器
    函数的其他关键点*与**,函数的对象可以当做变量去使用,函数的嵌套,名称空间
    python函数,应用与讲解
    文件处理方式
    html-04 html骨架
    html-03 Web标准
    html-02 浏览器内核
  • 原文地址:https://www.cnblogs.com/M-LittleBird/p/5907742.html
Copyright © 2020-2023  润新知