Asp.Net MVC FilterAttribute特性、讀取xml反序列化、NLog實戰系列文章
首先新建一個MVC project。
一、NLog的配置。
作者:Jarosław Kowalski <jaak@jkowalski.net>
翻譯:CrazyCoder
原文:http://www.nlog-project.org/config.html
更多關於NLog的中文文章,請參考《NLog文章系列》。
(1)在當前project中引用NLog相關dll文件。

此時會發現project底下多了兩個文件。可以自己新建一個Config文件夾,把這兩個文件移進去。

(2)接下來就是根據自己個人需求配置NLog。
$1、到Web.Config添加以下配置。
1 <configuration>
2 <configSections>
3 <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
4 </configSections>
5 <nlog>
6 <include file="${basedir}/Config/NLog.config" /><!--包含文件 此處配置為前面引用NLog時添加的NLog.config文件-->
7 </nlog>
8 </configuration>
$2、一個新添加的NLog.config是沒有指定"輸出目標“和"規則"的,所以我們自己添加targets和rules。
1 <targets>
2 <target name="toLogFile" xsi:type="File"
3 archiveAboveSize="2097152"
4 fileName="d:/LogFiles/NLogTest/${shortdate}.log"
5 archiveFileName="d:/LogFiles/NLogTest/{#}.txt"
6 archiveNumbering="DateAndSequence"
7 archiveEvery="Day"
8 maxArchiveFiles="90"
9 archiveDateFormat="yyyy-MM-dd"
10 layout="TimeStamp:${date} —${machinename} - ${message}"
11 />
12 <wrapper-target xsi:type="AsyncWrapper" name="asyncFile">
13 <target-ref name="toLogFile"/>
14 </wrapper-target>
15 </targets>
16
17 <rules>
18 <!-- add your logging rules here -->
19 <logger name="*" minlevel ="Info" writeTo="asyncFile"></logger>
20 </rules>
二、編寫異常錯誤的處理代碼。
$1、讀取ErrorCode配置文件中數據。
1 namespace NlogTest.Common
2 {
3 [XmlRoot("ErrorConfig")]
4 public class ErrorCodeConfig
5 {
6 [XmlArray("ErrorCodes")]
7 [XmlArrayItem("Error", typeof(ErrorCode))]
8 public List<ErrorCode> ErrorCodes { get; set; }
9
10 public static ErrorCodeConfig Config
11 {
12 get
13 {
14 return XmlHelper.XmlToEntity<ErrorCodeConfig>("ErrorCode");
15 }
16 }
17
18 public static ErrorCode GetError(string errorCode)
19 {
20 return Config.ErrorCodes.FirstOrDefault(e => e.Code == errorCode);
21 }
22 }
23
24 public class ErrorCode
25 {
26 [XmlAttribute("code")]
27 public string Code { get; set; }
28
29 [XmlAttribute("msg")]
30 public string Message { get; set; }
31
32 [XmlAttribute("PartialPage")]
33 public string PartialPage { get; set; }
34
35 [XmlAttribute("level")]
36 public string Level { get; set; }
37 }
38 }
xmlHelper類:
1 namespace NlogTest.Common
2 {
3 public class XmlHelper
4 {
5 public static string GetXmlPath(string XmlName)
6 {
7 string filePath = string.Empty;
8 filePath = System.Web.HttpContext.Current.Server.MapPath(string.Concat("", "~/Config/"+XmlName + ".Config"));
9
10 return filePath;
11 }
12
13 public static List<T> XmlToEntityList<T>(string XmlName)
14 {
15 string xmlPath = GetXmlPath(XmlName);
16 XmlSerializer serializer = new XmlSerializer(typeof(List<T>));
17 Object obj = new Object();
18
19 if (File.Exists(xmlPath))
20 {
21 using (StreamReader reader = new StreamReader(xmlPath))
22 {
23 try
24 {
25 obj = serializer.Deserialize(reader);
26 }
27 catch (Exception ex)
28 {
29 //Here put your code witch dealing with exception
30 }
31 }
32 }
33 return (List<T>)obj;
34 }
35
36 public static T XmlToEntity<T>(string XmlName)
37 {
38 string xmlPath = GetXmlPath(XmlName);
39 XmlSerializer serializer = new XmlSerializer(typeof(T));
40 Object obj = new Object();
41
42 if (File.Exists(xmlPath))
43 {
44 using (StreamReader reader = new StreamReader(xmlPath))
45 {
46 try
47 {
48 obj = serializer.Deserialize(reader);
49 }
50 catch (Exception ex)
51 {
52 //Here put your code witch dealing with exception
53 }
54 }
55 }
56 return (T)obj;
57 }
58 }
59 }
ErrorConfig文件:
1 <?xml version="1.0" encoding="utf-8"?> 2 <ErrorConfig> 3 <ErrorCodes> 4 <!--Service Errors--> 5 <Error code="1000500" description="GeneralServiceError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 6 <!--Address--> 7 <Error code="1101500" description="GetCitiesError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 8 <Error code="1102500" description="GetStatesError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 9 <Error code="1103500" description="GetPostalCodesError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 10 <!--AgreementDoc--> 11 <Error code="1201500" description="GetAgreementDocError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 12 <!--Image Upload--> 13 <Error code="1301500" description="PostImagesError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 14 <Error code="1302500" description="ImageStreamEmpty" msg="" PartialPage="ErrorPartial/GlobalError" level="Info"/> 15 <!--Agreement--> 16 <Error code="1401500" description="PostAgreementError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 17 <Error code="1402500" description="ValidateAgreementError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 18 <Error code="1403400" description="InvalidGovernmentId" msg="" PartialPage="ErrorPartial/GlobalError" level="Info"/> 19 <Error code="1404500" description="AgreementProcessorError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 20 <Error code="1405500" description="InvalidEmailId" msg="" PartialPage="ErrorPartial/GlobalError" level="Info"/> 21 <Error code="1406500" description="DuplicateConsultant" msg="" PartialPage="ErrorPartial/GlobalError" level="Info"/> 22 <!--Consultant--> 23 <Error code="1501500" description="GetConsultantError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 24 <Error code="1502500" description="GetConsultantListError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 25 <Error code="1503500" description="GetUnitMemberListError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 26 <Error code="1504400" description="ConsultantIdNotEmpty" msg="" PartialPage="ErrorPartial/GlobalError" level="Info"/> 27 <Error code="1505400" description="ConsultantListLessParams" msg="" PartialPage="ErrorPartial/GlobalError" level="Info"/> 28 <Error code="1506500" description="ConsultantIsInRoleError" msg="" PartialPage="ErrorPartial/GlobalError" level="Info"/> 29 <!--Domain--> 30 <Error code="1601500" description="GetBanksError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 31 <Error code="1602500" description="GetRacesError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 32 <Error code="1603500" description="ValidateGovernmentIdError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 33 <Error code="1604500" description="GetGateError" msg="" PartialPage="ErrorPartial/GlobalError" level="Error"/> 34 35 <!--end service--> 36 37 <!--Web Errors--> 38 39 <!--Unexpected Web Error--> 40 <Error code="2000500" description="" msg="" PartialPage="ErrorPartial/GlobalError" level="Info"></Error> 41 42 <!--Home Controller Error start with 1--> 43 <Error code="2101400" description="" msg="RecruitInfo_Not_Eligible" PartialPage="ErrorPartial/NotEligibleRecruit" level="Info"></Error> 44 45 <!--Reminder Controller Error start with 2--> 46 <!--PersonalInformation Controller Error start with 3--> 47 <!--Review Controller Error start with 4--> 48 <!--Imageupload Controller Error start with 5--> 49 50 <!--confirmation Controller Error start with 6--> 51 <Error code="2601400" description="Session ConfirmationViewModel is null" msg="" PartialPage="ErrorPartial/GlobalError" level="Info"/> 52 53 <Error code="2701500" description="can not access service" msg="" PartialPage="ErrorPartial/GlobalError" level="Info"/> 54 55 <!--end Web Errors--> 56 57 </ErrorCodes> 58 </ErrorConfig>
$2、 封裝一個Log處理異常錯誤的類庫—LogUtil.
1 public class LogUtil
2 {
3 private static object mutex = new object();
4
5 private static Logger logger = LogManager.GetCurrentClassLogger();
6
7 private static LogUtil _instance = null;
8
9 public static LogUtil Instance
10 {
11 get
12 {
13 if (_instance == null)
14 {
15 lock (mutex)
16 {
17 if (_instance == null)
18 {
19 _instance = new LogUtil();
20 }
21 }
22 }
23 return _instance;
24 }
25 }
26
27 public static void Log(int errorCode, string message = null, Exception ex = null)
28 {
29 ErrorCode errObj = ErrorCodeConfig.GetError(errorCode.ToString());
30 if (errObj == null)
31 {
32 Instance.LogWarn("Error code " + errorCode + " has no definition.");
33 return;
34 }
35
36 StringBuilder msgBuilder = GenerateMessage(errorCode.ToString(), message, ex);
37
38 string methodName = "Log" + errObj.Level;
39 MethodInfo method = typeof(LogUtil).GetMethod(methodName);
40 if (method == null)
41 {
42 Instance.LogWarn("log level wrong,please check ErrorCode.Config.level name is " + errObj.Level);
43 return;
44 }
45 method.Invoke(Instance, new object[] { msgBuilder.ToString() });
46
47 }
48
49 public static void LogDebug(string message)
50 {
51 logger.Log(LogLevel.Debug, message);
52 }
53
54 public static void LogError(string message)
55 {
56 logger.Log(LogLevel.Error, message);
57 }
58
59 public void LogErrorException(Exception ex)
60 {
61 LogException(LogLevel.Error, ex);
62 }
63
64 public void LogFatalException(Exception ex)
65 {
66 LogException(LogLevel.Fatal, ex);
67 }
68
69 public void LogFatal(string message)
70 {
71 logger.Log(LogLevel.Fatal, message);
72 }
73
74 public static void LogInfo(string message)
75 {
76 logger.Log(LogLevel.Info, message);
77 }
78
79 public void LogOff(string message)
80 {
81 logger.Log(LogLevel.Off, message);
82 }
83
84 public void LogTrace(string message)
85 {
86 logger.Log(LogLevel.Trace, message);
87 }
88
89 public void LogWarn(string message)
90 {
91 logger.Log(LogLevel.Warn, message);
92 }
93
94
95 private static void LogException(LogLevel level, Exception ex)
96 {
97 logger.Log(level, GetExceptionMessage(ex));
98 }
99
100 private static string GetExceptionMessage(Exception ex)
101 {
102 string message = ex.Message;
103 string stackTrace = ex.StackTrace;
104 if (string.IsNullOrEmpty(stackTrace) && ex.InnerException != null)
105 {
106 stackTrace = ex.InnerException.StackTrace;
107 }
108 return message + "::" + stackTrace;
109 }
110
111 private static StringBuilder GenerateMessage(string errorCode, string message, Exception ex)
112 {
113 StringBuilder msgBuilder = new StringBuilder();
114 msgBuilder.Append("ErrorCode is " + errorCode);
115 msgBuilder.Append("\r\n");
116 if (!string.IsNullOrEmpty(message))
117 {
118 msgBuilder.Append(message);
119 msgBuilder.Append("\r\n");
120 }
121 if (ex != null)
122 {
123 msgBuilder.Append(GetExceptionMessage(ex));
124 msgBuilder.Append("\r\n");
125 }
126 return msgBuilder;
127 }
128 }
三、將LogUtil與MVC銜接上,該MVC中的FilterAttribute、IExceptionFilter出場了。
$1、定義個ErrorFilterAttribute繼承FilterAttribute、IExceptionFilter。
1 namespace NlogTest.FrameWork
2 {
3 public class ErrorFilterAttribute:FilterAttribute,IExceptionFilter
4 {
5 private const int commonError = 2000500;
6
7 public void OnException(ExceptionContext filterContext)
8 {
9 int errorCode = commonError;
10 Exception exception = filterContext.Exception;
11
12 if (exception is ErrorCodeException)
13 {
14 errorCode = ((ErrorCodeException)exception).ErrorCode;
15 }
16 string message = "Error";
17 LogUtil.Log(errorCode,ex:exception,message:message);
18 }
19 }
20 }
$2、將ErrorFilterAttribute注冊到App_Start底下的FilterConfig中,這樣做的目的是利用MVC中過濾器對全局的controller進行處理。簡而言之,比如任意一個controller中action拋出異常錯誤,這裡都會檢測到並作為日志記錄的接口開始對這些異常錯誤進行記錄。
測試效果:
在HomeController中寫一段會發生錯誤的代碼:

到在輸出目標位置中找對應log文件:

激動的時刻到來了
PS:至此整個Demo算是完成了,快過年了,公司也沒啥事,自己搗鼓點東西,基礎比較差,就當練手。經過這次,我明白了一件事,平時多積累點小知識點,可以匯集起來再實現一個小功能,新舊知識結合,挺好。
源碼:https://coding.net/u/NickZhao/p/MVC-NLog/git