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

目前博客系统已经数据库创建、以及依赖注入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. java接口中定义成员变量

    //抽象类中可以定义如下成员变量:public abstract class People { public String name; public int age; public abstract ...

  2. 在 Azure 上使用 Docker运行 Mono

    Docker 是最近相当热门的一个名词,它是一个基于 Linux Container 的轻量化的虚拟技术,而微软也相当积极与 Docker 合作,在 Azure 上支持这个火热的技术,并且提供简单的方 ...

  3. .NET中那些所谓的新语法之四:标准查询运算符与LINQ

    开篇:在上一篇中,我们了解了预定义委托与Lambda表达式等所谓的新语法,这一篇我们继续征程,看看标准查询运算符和LINQ.标准查询运算符是定义在System.Linq.Enumerable类中的50 ...

  4. 修改Hosts为何不生效,是DNS缓存?

    Update: 如果浏览器使用了代理工具,修改 Hosts 也不会生效.这里是因为,浏览器会优先考虑代理工具(如添加 pac 文件.SwitchySharp等)的代理,建议调试的时候先关闭这些代理. ...

  5. 使用shell/python获取hostname/fqdn释疑

    一直以来被Linux的hostname和fqdn(Fully Qualified Domain Name)困惑了好久,今天专门抽时间把它们的使用细节弄清了. 一.设置hostname/fqdn 在Li ...

  6. Node.js + Web Socket 打造即时聊天程序嗨聊

    前端一直是一块充满惊喜的土地,不仅是那些富有创造性的页面,还有那些惊赞的效果及不断推出的新技术.像node.js这样的后端开拓者直接将前端人员的能力扩大到了后端.瞬间就有了一统天下的感觉,来往穿梭于前 ...

  7. Go语言实战 - 创业进行时之创业伊始

    在工作了10年之后,我于32岁的年纪在两个月前辞职创业了. 简单介绍一下之前的整个职业生涯,挺典型的,工程师 –> 资深工程师 –> 架构师 –> 项目经理 –> 部门经理,可 ...

  8. Google Chrome调试js入门

    平常在开发过程中,经常会接触到前端页面.那么对于js的调试那可是家常便饭,不必多说.最近一直在用火狐的Firebug,但是不知道怎么的不好使了.网上找找说法,都说重新安装狐火浏览器就可以了,但是我安装 ...

  9. react native 入门实践

    上周末开始接触react native,版本为0.37,边学边看写了个demo,语法使用es6/7和jsx.准备分享一下这个过程.之前没有native开发和react的使用经验,不对之处烦请指出.希望 ...

  10. Atitit事件代理机制原理 基于css class的事件代理

    Atitit事件代理机制原理 基于css class的事件代理 1.1. 在javasript中delegate这个词经常出现,看字面的意思,代理.委托1 1.2. 事件代理1 1.3. 代理标准化规 ...