一、回顧系統進度以及本章概要
目前博客系統已經數據庫創建、以及依賴注入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 }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中下載到。
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中找到。
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框架
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下運行。
在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" />表示什麼級別的日志對應放在哪個配置裡面。
這裡日志保存在發布站點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 View Code
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 }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
直接在創建的控制器下集成:
接下來就是准備實現頁面布局,先做個簡單的前台查看,後台分布的功能,然後在一步一步的完善,希望大家多多指點,多多支持,謝謝了。