原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(11)-系统日志和异常的处理①
系统需要越来越自动化,我们需要引入日志记录和异常捕获
管理员的操作记录需要被记录,看出哪些模块是频繁操作,分析哪些是不必要的功能,哪些是需要被优化的。
系统的异常需要被捕获,而不是将系统出错显示出来给用户就不了了知。我们需要异常日志不断改进系统。
我们老说用户,我们还没有用户权限的表,所以我们在Home中先加入一个虚拟用户吧!
首先我们创建一个用户类AccountModel放在App.Models下的Sys文件夹下
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace App.Models.Sys { public class AccountModel { public string Id { get; set; } public string TrueName { get; set; } } }
在HomeController或者AccountController插入代码
AccountModel account = new AccountModel(); account.Id = "admin"; account.TrueName = "admin"; Session["Account"] = account;
下面将带来系统日志的记录,主要记录管理员的增、删、改等操作的成功与失败的异常记录
日志插件有著名的log4net,可以输出多种格式,如文本,xml,数据库等,我们没有必要做到这么强大,我们只做符合系统的就可以了,记录到数据库,方便做统计等操
作,我们何时何地记录日志?
- 在Controller层做记录;
- 当用户的操作成功时记录;
- 当用户的操作失败时记录;
首先创建数据库存放表:SysLog
USE DB GO /****** Object: Table [dbo].[SysLog] Script Date: 11/20/2013 21:13:38 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO SET ANSI_PADDING ON GO CREATE TABLE [dbo].[SysLog]( [Id] [varchar](50) NOT NULL, --GUID [Operator] [varchar](50) NULL,--操作人 [Message] [varchar](500) NULL,--操作信息 [Result] [varchar](20) NULL,--结果 [Type] [varchar](20) NULL,--操作类型 [Module] [varchar](20) NULL,--操作模块 [CreateTime] [datetime] NULL,--操作事件 CONSTRAINT [PK_SysLog] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO SET ANSI_PADDING OFF GO
EF更新模型,创建SysLogModel类放在App.Models下的Sys文件夹下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.DataAnnotations; namespace App.Models.Sys { public class SysLogModel { [Display(Name = "ID")] public string Id { get; set; } [Display(Name = "操作人")] public string Operator { get; set; } [Display(Name = "信息")] public string Message { get; set; } [Display(Name = "结果")] public string Result { get; set; } [Display(Name = "类型")] public string Type { get; set; } [Display(Name = "模块")] public string Module { get; set; } [Display(Name = "创建时间")] public DateTime? CreateTime { get; set; } } }
创建SysLog的BLL层和DAL层
using System; using App.Models; using System.Linq; namespace App.IDAL { public interface ISysLogRepository { int Create(SysLog entity); void Delete(DBContainer db, string[] deleteCollection); IQueryable<SysLog> GetList(DBContainer db); SysLog GetById(string id); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using App.Models; using App.IDAL; namespace App.DAL { public class SysLogRepository:IDisposable, ISysLogRepository { /// <summary> /// 获取集合 /// </summary> /// <param name="db">数据库</param> /// <returns>集合</returns> public IQueryable<SysLog> GetList(DBContainer db) { IQueryable<SysLog> list = db.SysLog.AsQueryable(); return list; } /// <summary> /// 创建一个对象 /// </summary> /// <param name="db">数据库</param> /// <param name="entity">实体</param> public int Create(SysLog entity) { using (DBContainer db = new DBContainer()) { db.SysLog.AddObject(entity); return db.SaveChanges(); } } /// <summary> /// 删除对象集合 /// </summary> /// <param name="db">数据库</param> /// <param name="deleteCollection">集合</param> public void Delete(DBContainer db, string[] deleteCollection) { IQueryable<SysLog> collection = from f in db.SysLog where deleteCollection.Contains(f.Id) select f; foreach (var deleteItem in collection) { db.SysLog.DeleteObject(deleteItem); } } /// <summary> /// 根据ID获取一个实体 /// </summary> /// <param name="id"></param> /// <returns></returns> public SysLog GetById(string id) { using (DBContainer db = new DBContainer()) { return db.SysLog.SingleOrDefault(a => a.Id == id); } } public void Dispose() { } } }
using System; using System.Collections.Generic; using App.Common; using App.Models; namespace App.IBLL { public interface ISysLogBLL { List<SysLog> GetList(ref GridPager pager,string queryStr); SysLog GetById(string id); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Practices.Unity; using App.IDAL; using App.Common; using App.Models.Sys; using App.Models; using App.IBLL; namespace App.BLL { public class SysLogBLL: ISysLogBLL { [Dependency] public ISysLogRepository logRepository { get; set; } public List<SysLog> GetList(ref GridPager pager, string queryStr) { DBContainer db = new DBContainer(); List<SysLog> query = null; IQueryable<SysLog> list = logRepository.GetList(db); if (!string.IsNullOrWhiteSpace(queryStr)) { list = list.Where(a => a.Message.Contains(queryStr) || a.Module.Contains(queryStr)); pager.totalRows = list.Count(); } else { pager.totalRows = list.Count(); } if (pager.order == "desc") { query = list.OrderByDescending(c => c.CreateTime).Skip((pager.page - 1) * pager.rows).Take(pager.rows).ToList(); } else { query = list.OrderBy(c => c.CreateTime).Skip((pager.page - 1) * pager.rows).Take(pager.rows).ToList(); } return query; } public SysLog GetById(string id) { return logRepository.GetById(id); } } }
创建SysLog的Controller
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using App.Common; using App.Models; using Microsoft.Practices.Unity; using App.IBLL; using App.Models.Sys; namespace App.Admin.Controllers { public class SysLogController : Controller { // // GET: /SysLog/ [Dependency] public ISysLogBLL logBLL { get; set; } public ActionResult Index() { return View(); } public JsonResult GetList(GridPager pager, string queryStr) { List<SysLog> list = logBLL.GetList(ref pager, queryStr); var json = new { total = pager.totalRows, rows = (from r in list select new SysLogModel() { Id= r.Id, Operator= r.Operator, Message= r.Message, Result= r.Result, Type= r.Type, Module= r.Module, CreateTime= r.CreateTime }).ToArray() }; return Json(json); } #region 详细 public ActionResult Details(string id) { SysLog entity = logBLL.GetById(id); SysLogModel info = new SysLogModel() { Id = entity.Id, Operator = entity.Operator, Message = entity.Message, Result = entity.Result, Type = entity.Type, Module = entity.Module, CreateTime = entity.CreateTime, }; return View(info); } #endregion } }
创建SysLog的Index视图和Details视图,我们暂时提示Index和Details,删除功能童鞋们自己扩展,我们有样例程序SysSample嘛,什么都是必然的了
@using App.Admin; @using App.Common; @using App.Models.Sys; @{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Index_Layout.cshtml"; } <script src="~/Scripts/jquery.easyui.plus.js"></script> <div class="mvctool"> <input id="txtQuery" type="text" class="searchText"/> <a id="btnQuery" style="float: left;" class="l-btn l-btn-plain"><span class="l-btn-left"><span class="l-btn-text icon-search" style="padding-left: 20px;">查询</span></span></a><div class="datagrid-btn-separator"></div> <a id="btnDetails" style="float: left;" class="l-btn l-btn-plain"><span class="l-btn-left"><span class="l-btn-text icon-details" style="padding-left: 20px;">详细</span></span></a><div class="datagrid-btn-separator"></div> <a id="btnDelete" style="float: left;" class="l-btn l-btn-plain"><span class="l-btn-left"><span class="l-btn-text icon-remove" style="padding-left: 20px;">删除</span></span></a> </div> <table id="List"></table> <div id="Pager"></div> <div id="modalwindow" class="easyui-window" data-options="modal:true,closed:true,minimizable:false,shadow:false"></div> @*Jqgrid*@ <script type="text/javascript"> //ifram 返回 function frameReturnByClose() { $("#modalwindow").window('close'); } function frameReturnByReload(flag) { if (flag) $("#List").datagrid('load'); else $("#List").datagrid('reload'); } function frameReturnByMes(mes) { $.messageBox5s('提示', mes); } $(function () { $('#List').datagrid({ url: '/SysLog/GetList', width: $(window).width() - 10, methord: 'post', height: $(window).height() - 35, fitColumns: true, sortName: 'Id', sortOrder: 'desc', idField: 'Id', pageSize: 15, pageList: [15, 20, 30, 40, 50], pagination: true, striped: true, //奇偶行是否区分 singleSelect: true,//单选模式 columns: [[ { field: 'Id', title: 'ID', width: 40, hidden: true }, { field: 'Operator', title: '操作人', width: 40 }, { field: 'Message', title: '信息', width: 280 }, { field: 'Result', title: '结果', width: 40, align: 'center' }, { field: 'Type', title: '类型', width: 40, align: 'center' }, { field: 'Module', title: '模块', width: 60, align: 'center' }, { field: 'CreateTime', title: '添加时间', width: 65, align: 'center' } ]] }); }); </script> @*operation*@ <script type="text/javascript"> $(function () { $("#btnDetails").click(function () { var row = $('#List').datagrid('getSelected'); if (row != null) { $("#modalwindow").html("<iframe width='100%' height='98%' frameborder='0' src='/SysLog/Details?id=" + row.Id + "'></iframe>"); $("#modalwindow").window({ title: '详细', width: 500, height: 400, iconCls: 'icon-details' }).window('open'); } else { $.messageBox5s('提示', '请选择要操作的行!'); } }); $("#btnQuery").click(function () { var queryStr = $("#txtQuery").val(); //如果查询条件为空默认查询全部 if (queryStr == null) { queryStr = "%"; } $('#List').datagrid({ url: '/SysLog/GetList?queryStr=' + encodeURI(queryStr)}); }); }); </script>
@model App.Models.Sys.SysLogModel @using App.Common; @using App.Admin; @using App.Models.Sys; @{ ViewBag.Title = "Details"; Layout = "~/Views/Shared/_Index_LayoutEdit.cshtml"; } <script type="text/javascript"> $(function () { $("#btnReturn").click(function () { window.parent.frameReturnByClose(); }); }); </script> <div class="mvctool bgb"> <a id="btnReturn" style="float: left;" class="l-btn l-btn-plain"><span class="l-btn-left"><span class="l-btn-text icon-return" style="padding-left: 20px;">返回</span></span></a> </div> @using (Html.BeginForm()) { <table class="form_table setinput355"> <tbody> <tr> <th> @Html.LabelFor(model => model.Operator) </th> <td> @Html.EditorFor(model => model.Operator) </td> </tr> <tr> <th> @Html.LabelFor(model => model.Message) </th> <td> @Html.TextAreaFor(model => model.Message, new { @style="height:100px;"}) </td> </tr> <tr> <th> @Html.LabelFor(model => model.Result) </th> <td> @Html.EditorFor(model => model.Result) </td> </tr> <tr> <th> @Html.LabelFor(model => model.Type) </th> <td> @Html.EditorFor(model => model.Type) </td> </tr> <tr> <th> @Html.LabelFor(model => model.Module) </th> <td> @Html.EditorFor(model => model.Module) </td> </tr> <tr> <th> @Html.LabelFor(model => model.CreateTime) </th> <td> @Html.TextBoxFor(model => model.CreateTime) </td> </tr> </tbody> </table> }
有看过前面的童鞋,应该很熟悉这一步很机械化的创建了
- 创建数据表
- 更新到EF
- 创建BLL和DAL层
- 创建Model
- 创建爱你Controller
- 创建View
- 注入到容器
- 运行
你看了不累我都觉得累了,我们以后会讲用T4,我们自动生成
预览下效果,你会发现我们的左边的菜单栏可以点出来了。oh yeh...(别忘记注入)
分页和详细都没有问题了。
接下来是是异常的捕获,我们在何时处理异常?我们没有处理的异常该怎么办?我们处理异常时出现异常怎么又怎么办?反正我是要捕获到这异常了...、
我们一般先对数据进行判断避免捕获异常,因为try catch会降低程序的性能,我们一般在业务层捕获异常,处理逻辑容易导致异常
- 处理异常出错,我们将输出文本格式,来记录异常
- 我们将写全局异常捕获来拦截异常
- 你觉得我们的系统后盾还不够强大吗?
创建异常存放数据表SysException
USE DB GO /****** Object: Table [dbo].[SysException] Script Date: 11/20/2013 21:17:44 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO SET ANSI_PADDING ON GO CREATE TABLE [dbo].[SysException]( [Id] [varchar](50) NOT NULL, --GUID [HelpLink] [varchar](500) NULL,--帮助链接 [Message] [varchar](500) NULL,--异常信息 [Source] [varchar](500) NULL,--来源 [StackTrace] [text] NULL,--堆栈 [TargetSite] [varchar](500) NULL,--目标页 [Data] [varchar](500) NULL,--程序集 [CreateTime] [datetime] NULL,--发生时间 CONSTRAINT [PK_SysException] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO SET ANSI_PADDING OFF GO
EF更新模型,创建SysExceptionModel类放在App.Models下的Sys文件夹下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.DataAnnotations; namespace App.Models.Sys { /// <summary> /// 异常处理类 /// </summary> public class SysExceptionModel { [Display(Name = "ID")] public string Id { get; set; } [Display(Name = "帮助链接")] public string HelpLink { get; set; } [Display(Name = "错误信息")] public string Message { get; set; } [Display(Name = "来源")] public string Source { get; set; } [Display(Name = "堆栈")] public string StackTrace { get; set; } [Display(Name = "目标页")] public string TargetSite { get; set; } [Display(Name = "程序集")] public string Data { get; set; } [Display(Name = "发生时间")] public DateTime? CreateTime { get; set; } } }
创建SysException的BLL层和DAL层
using System; using App.Models; using System.Linq; namespace App.IDAL { public interface ISysExceptionRepository { int Create(SysException entity); IQueryable<SysException> GetList(DBContainer db); SysException GetById(string id); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using App.Models; using App.IDAL; namespace App.DAL { public class SysExceptionRepository:IDisposable, ISysExceptionRepository { /// <summary> /// 获取集合 /// </summary> /// <param name="db">数据库</param> /// <returns>集合</returns> public IQueryable<SysException> GetList(DBContainer db) { IQueryable<SysException> list = db.SysException.AsQueryable(); return list; } /// <summary> /// 创建一个对象 /// </summary> /// <param name="db">数据库</param> /// <param name="entity">实体</param> public int Create( SysException entity) { using (DBContainer db = new DBContainer()) { db.SysException.AddObject(entity); return db.SaveChanges(); } } /// <summary> /// 根据ID获取一个实体 /// </summary> /// <param name="id"></param> /// <returns></returns> public SysException GetById(string id) { using (DBContainer db = new DBContainer()) { return db.SysException.SingleOrDefault(a => a.Id == id); } } public void Dispose() { } } }
using System; using System.Collections.Generic; using App.Common; using App.Models; namespace App.IBLL { public interface ISysExceptionBLL { List<SysException> GetList(ref GridPager pager,string queryStr); SysException GetById(string id); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Practices.Unity; using App.IDAL; using App.Common; using App.Models.Sys; using App.Models; using App.IBLL; namespace App.BLL { public class SysExceptionBLL: ISysExceptionBLL { [Dependency] public ISysExceptionRepository exceptionRepository { get; set; } public List<SysException> GetList(ref GridPager pager, string queryStr) { DBContainer db = new DBContainer(); List<SysException> query = null; IQueryable<SysException> list = exceptionRepository.GetList(db); if (!string.IsNullOrWhiteSpace(queryStr)) { list = list.Where(a => a.Message.Contains(queryStr)); pager.totalRows = list.Count(); } else { pager.totalRows = list.Count(); } if (pager.order == "desc") { query = list.OrderByDescending(c => c.CreateTime).Skip((pager.page - 1) * pager.rows).Take(pager.rows).ToList(); } else { query = list.OrderBy(c => c.CreateTime).Skip((pager.page - 1) * pager.rows).Take(pager.rows).ToList(); } return query; } public SysException GetById(string id) { return exceptionRepository.GetById(id); } } }
创建SysException的Controller
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Reflection; using System.Text; using App.Common; using App.Models; using App.IBLL; using App.Models.Sys; using Microsoft.Practices.Unity; namespace App.Admin.Controllers { public class SysExceptionController : Controller { // // GET: /SysException/ [Dependency] public ISysExceptionBLL exceptionBLL { get; set; } public ActionResult Index() { return View(); } public JsonResult GetList(GridPager pager, string queryStr) { List<SysException> list = exceptionBLL.GetList(ref pager, queryStr); var json = new { total = pager.totalRows, rows = (from r in list select new SysException() { Id = r.Id, HelpLink =r.HelpLink, Message = r.Message, Source = r.Source, StackTrace = r.StackTrace, TargetSite = r.TargetSite, Data = r.Data, CreateTime = r.CreateTime }).ToArray() }; return Json(json); } #region 详细 public ActionResult Details(string id) { SysException entity = exceptionBLL.GetById(id); SysExceptionModel info = new SysExceptionModel() { Id = entity.Id, HelpLink = entity.HelpLink, Message = entity.Message, Source = entity.Source, StackTrace = entity.StackTrace, TargetSite = entity.TargetSite, Data = entity.Data, CreateTime = entity.CreateTime, }; return View(info); } #endregion } }
创建SysException的Index视图和Details视图
@using App.Admin; @using App.Common; @using App.Models.Sys; @{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Index_Layout.cshtml"; } <script src="~/Scripts/jquery.easyui.plus.js"></script> <div class="mvctool"> <input id="txtQuery" type="text" class="searchText"/> <a id="btnQuery" style="float: left;" class="l-btn l-btn-plain"><span class="l-btn-left"><span class="l-btn-text icon-search" style="padding-left: 20px;">查询</span></span></a><div class="datagrid-btn-separator"></div> <a id="btnDetails" style="float: left;" class="l-btn l-btn-plain"><span class="l-btn-left"><span class="l-btn-text icon-details" style="padding-left: 20px;">详细</span></span></a><div class="datagrid-btn-separator"></div> <a id="btnDelete" style="float: left;" class="l-btn l-btn-plain"><span class="l-btn-left"><span class="l-btn-text icon-remove" style="padding-left: 20px;">删除</span></span></a> </div> <table id="List"></table> <div id="Pager"></div> <div id="modalwindow" class="easyui-window" data-options="modal:true,closed:true,minimizable:false,shadow:false"></div> @*Jqgrid*@ <script type="text/javascript"> $(function () { $('#List').datagrid({ url: '/SysException/GetList', width: $(window).width() - 10, methord: 'post', height: $(window).height() - 35, fitColumns: true, sortName: 'Id', sortOrder: 'desc', idField: 'Id', pageSize: 15, pageList: [15, 20, 30, 40, 50], pagination: true, striped: true, //奇偶行是否区分 singleSelect: true,//单选模式 columns: [[ { field: 'Id', title: 'ID', width: 40, hidden: true }, { field: 'HelpLink', title: '帮助链接', width: 40 }, { field: 'Message', title: '异常信息', width: 200 }, { field: 'Source', title: '来源', width: 140 }, { field: 'StackTrace', title: '堆栈', width: 40, align: 'center' }, { field: 'TargetSite', title: '目标页', width: 40, align: 'center' }, { field: 'Data', title: '程序集', width: 60, align: 'center' }, { field: 'CreateTime', title: '发生时间', width: 65, align: 'center' } ]] }); }); </script> @*operation*@ <script type="text/javascript"> //ifram 返回 function frameReturnByClose() { $("#modalwindow").window('close'); } $(function () { $("#btnDetails").click(function () { var row = $('#List').datagrid('getSelected'); if (row != null) { $("#modalwindow").html("<iframe width='100%' height='98%' frameborder='0' src='/SysException/Details?id=" + row.Id + "'></iframe>"); $("#modalwindow").window({ title: '详细', width: 700, height: 400, iconCls: 'icon-details' }).window('open'); } else { $.messageBox5s('提示', '请选择要操作的行!'); } }); $("#btnQuery").click(function () { var queryStr = $("#txtQuery").val(); //如果查询条件为空默认查询全部 if (queryStr == null) { queryStr = "%"; } $('#List').datagrid({ url: '/SysException/GetList?queryStr=' + encodeURI(queryStr) }); }); }); </script>
@model App.Models.Sys.SysExceptionModel @using App.Admin; @using App.Common; @using App.Models.Sys; @{ ViewBag.Title = "Details"; Layout = "~/Views/Shared/_Index_LayoutEdit.cshtml"; } <script type="text/javascript"> $(function () { $("#btnReturn").click(function () { window.parent.frameReturnByClose(); }); }); </script> <div class="mvctool bgb"> <a id="btnReturn" style="float: left;" class="l-btn l-btn-plain"><span class="l-btn-left"><span class="l-btn-text icon-return" style="padding-left: 20px;">返回</span></span></a> </div> @using (Html.BeginForm()) { <div id="ErrMesList"> <div id="ErrMesListContent"> @Html.ValidationSummary(false) </div> </div> <table class="form_table setinput355"> <tbody> <tr> <th> @Html.LabelFor(model => model.HelpLink) </th> <td> @Html.EditorFor(model => model.HelpLink) </td> </tr> <tr> <th> @Html.LabelFor(model => model.Message) </th> <td> @Html.TextAreaFor(model => model.Message, new { @style = "height:100px;width:550px" }) </td> </tr> <tr> <th> @Html.LabelFor(model => model.Source) </th> <td> @Html.EditorFor(model => model.Source) </td> </tr> <tr> <th> @Html.LabelFor(model => model.StackTrace) </th> <td> @Html.TextAreaFor(model => model.StackTrace, new { @style = "height:100px;width:550px" }) </td> </tr> <tr> <th> @Html.LabelFor(model => model.TargetSite) </th> <td> @Html.TextAreaFor(model => model.TargetSite, new { @style = "height:100px;width:550px" }) </td> </tr> <tr> <th> @Html.LabelFor(model => model.Data) </th> <td> @Html.EditorFor(model => model.Data) </td> </tr> <tr> <th> @Html.LabelFor(model => model.CreateTime) </th> <td> @Html.TextBoxFor(model => model.CreateTime) </td> </tr> </tbody> </table> }
被忘记注入到容器。预览一下
由于时间关系,把异常和日志的应用放到一下讲吧。
然后我认为无目的的提供源码对园友的帮助是不大的,只能说你拥有一套源码,无论多漂亮都好,你自己不思考不动手,东西永远还是别人做出来的,真正遇到问题,是难解决,或者解决不了的,然而系统,我并没有完完全全把所有代码放出来,但是复杂的逻辑或者重点我都放出来了,正如上面,日志和异常的删除功能我没有放出源代码,就希望大家一起来完善这个强大的系统。
我希望大家如果有时间跟着来做,你肯定会受益匪浅