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

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

二、缓存机制实现

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

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 }

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 }

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

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 }

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

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 }

三、日志处理: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 }

2.在nuget中添加Nlog框架

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 }

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

在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>

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

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

4、日志测试

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

这里需要添加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

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

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

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

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

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

四、创建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 }

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 }

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

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

10月10日补充说明:

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

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

  1. 从零开始,搭建博客系统MVC5+EF6搭建框架(5),博客详情页、留言、轮播图管理、右侧统计博文

    一.博客系统进度回顾 上一遍博客介绍到,系统已经实现到了发布以及前台布局展示,接下来就是实现一些,详情页,留言.轮播图管理.右侧博文统计信息实现. 二.博客系统详情页实现 2.1先来看看详情页展示的效 ...

  2. 从零开始,搭建博客系统MVC5+EF6搭建框架(1),EF Code frist、实现泛型数据仓储以及业务逻辑

    前言      从上篇30岁找份程序员的工作(伪程序员的独白),文章开始,我说过我要用我自学的技术,来搭建一个博客系统,也希望大家给点意见,另外我很感谢博客园的各位朋友们,对我那篇算是自我阶段总结文章 ...

  3. 从零开始,搭建博客系统MVC5+EF6搭建框架(4)上,前后台页面布局页面实现,介绍使用的UI框架以及JS组件

    一.博客系统进度回顾以及页面设计 1.1页面设计说明 紧接前面基础基本完成了框架搭建,现在开始设计页面,前台页面设计我是模仿我博客园的风格来设计的,后台是常规的左右布局风格. 1.2前台页面风格 主页 ...

  4. 从零开始,搭建博客系统MVC5+EF6搭建框架(4)下,前后台布局实现、发布博客以及展示。

    一.博客系统进度回顾 目前已经完成了,前台展示,以及后台发布的功能,最近都在做这个,其实我在国庆的时候就可以弄完的,但是每天自己弄,突然最后国庆2天,连电脑都不想碰,所以就一直拖着,上一篇写了前端实现 ...

  5. 从零开始,搭建博客系统MVC5+EF6搭建框架(2),测试添加数据、集成Autofac依赖注入

    一.测试仓储层.业务层是否能实现对数据库表的操作 1.创建IsysUserInfoRepository接口来继承IBaseRepository父接口 namespace Wchl.WMBlog.IRe ...

  6. Django快速搭建博客系统

    Django快速搭建博客系统 一.开发环境 Windows 7(64bit) python 3.6   https://www.python.org/ Django 2.0  https://www. ...

  7. day14搭建博客系统项目

    day14搭建博客系统项目 1.下载代码包 [root@web02 opt]# git clone https://gitee.com/lylinux/DjangoBlog.git 2.使用pid安装 ...

  8. 【干货】利用MVC5+EF6搭建博客系统(四)(上)前后台页面布局页面实现,介绍使用的UI框架以及JS组件

    一.博客系统进度回顾以及页面设计 1.1页面设计说明 紧接前面基础基本完成了框架搭建,现在开始设计页面,前台页面设计我是模仿我博客园的风格来设计的,后台是常规的左右布局风格. 1.2前台页面风格 主页 ...

  9. 【干货】利用MVC5+EF6搭建博客系统(四)(下)前后台布局实现、发布博客以及展示

    二.博客系统后台布局实现 2.1.这里所用的是MVC的布局页来实现的,后台主要分为三部分:导航.菜单.主要内容 代码实现: 这里把后台单独放在一个区域里面,所以我这里建立一个admin的区域 在布局页 ...

随机推荐

  1. 纯jQuery-添加/修改/删除 标签,属性

    <h1>通过学习<精彩绝伦的jQuery>与W3C,大致了解JQuery的一些方法.</h1> PS:需要有一些前置条件,比如JQuery源代码,比如html就要有 ...

  2. 通过远程 http API 来控制 lnmp 环境的重启perl脚本

    #!/usr/bin/perl use DBD::mysql; use strict; use warnings; use DBI; use utf8; binmode(STDOUT, ':encod ...

  3. WPF - 属性系统 (1 of 4)

    本来我希望这一系列文章能够深入讲解WPF属性系统的实现以及XAML编译器是如何使用这些依赖项属性的,并在最后分析WPF属性系统的实际实现代码.但是在编写的过程中发现对WPF属性系统代码的讲解要求之前的 ...

  4. Nova PhoneGap框架 第九章 控件

    我们的框架中也提供了一些常用的控件,这些控件大多都依赖于我们的框架,也正是在我们的框架下才使得实现这些控件的变得更简单.但是我们的框架是不依赖与这些控件的,如果你用不上这些控件,你完全可以把相关的代码 ...

  5. ASP.NET MVC项目实践技巧

    原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com 在.NET开发初期,微软提供的WEB开发模型是WebForm,试图消除Web和桌面的隔阂,建立一致的开发体验.但是 ...

  6. Qt And MFC Mouse Over Tips

    Qt鼠标提示分析说明 关于鼠标停留在控件上面,显示提示内容的方法. 对于Qt来说, Qt的某一个控件类, 如果属于GUI的, 那么这个控件类会有一个setToolTip(QString text)的方 ...

  7. Atitit 图像处理知识点体系知识图谱 路线图attilax总结 v4 qcb.xlsx

    Atitit 图像处理知识点体系知识图谱 路线图attilax总结 v4 qcb.xlsx 分类 图像处理知识点体系 v2 qb24.xlsx 分类 分类 理论知识 图像金字塔 常用底层操作 卷积扫描 ...

  8. Drupal8重命名上传的中文名文件

    完整的模块代码文件在Coding.net上,想直接使用的请前往下载:https://coding.net/u/yamus/p/chinese_rename/git/tree/master 最近吧Dru ...

  9. iOS-App上架流程

    前言:作为一名IOS开发者,把开发出来的App上传到App Store是必须的.下面就来详细介绍下具体流程. 1.打开苹果开发者中心:https://developer.apple.com 打开后点击 ...

  10. jQuery 2.0.3 源码分析 事件体系结构

    那么jQuery事件处理机制能帮我们处理那些问题? 毋容置疑首先要解决浏览器事件兼容问题 可以在一个事件类型上添加多个事件处理函数,可以一次添加多个事件类型的事件处理函数 提供了常用事件的便捷方法 支 ...