[转载]ASP.NET MVC—项目中用到的扩展 – 迭戈 – 博客园.
摘要:本人用ASP.NET MVC开发网站已经有半年的时间了(半年的web开发经验,之前没有做过web开发,呵呵),项目中摸爬滚打,多少也积累了一些经验。写出来,一是自己的总结,二是各位大拿给提提意见。
1、关于页面中有多个Submit按钮的实现。
如果您的view要显示一些列表,那么对应的URL可能是这样:/Product/List,view的名字就是List,如果您对应的 Action名称也使用List,显然不是很明智,因为这个Action使用一个动词的形式更好,比如:GetList,那么您就需要用到
ActionNameAttribute
,对于的Action写成这样
[ActionName("Test")] public ActionResult Index()
页面中有多个Submit按钮,提交的时候如何确定执行哪个Action呢?我们可以和ActionNameAttribute一样继承ActionNameSelectorAttribute,通过这个选择器来实现页面多个Submit按钮的提交。
因为被点击的Submit标签(name和value值)会post到服务器(可用状态下),所以在view里面给每一个Submit的name属性设置一个值即可。对于的Action写法如下:
[AcceptVerbs(HttpVerbs.Post), MultiSubmitButtonSelector("SearchTest")] public ActionResult SearchTest()
MultiSubmitButtonSelector的实现和MVC已有的ActionNameAttribute实现类似,具体代码如下:
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class MultiSubmitButtonSelectorAttribute : ActionNameSelectorAttribute { public string SubmitButtonName { private set; get; } public MultiSubmitButtonSelectorAttribute(string submitButtonName) { SubmitButtonName = submitButtonName; } public override bool IsValidName(ControllerContext controllerContext, string actionName, System.Reflection.MethodInfo methodInfo) { if (string.IsNullOrEmpty(SubmitButtonName)) { return false; } return controllerContext.HttpContext.Request.Form[SubmitButtonName] != null; } }
即:遍历Controller中所有具有ActionNameSelectorAttribute特性的Action,用其标注的 SubmitButtonName对post进来的数据进行取值操作,如果有值,说明Submit对应的正是这个Action。如果遍历结束,依然找不到 需要执行的Action,那么会执行该Form要提交到的Action。
这样就解决了,一个Form里面有多个submit的情况,需要注意的是,当submit被点击之后不能将其变为不可用,否则无法将该submit提交到服务器端,也就找不到对应的Action了。
2、生成并导出Excel(CSV)
这样的方法,默认的框架里面并没有提供,我们要自己动手。我在项目里面使用的生成Excel(CSV)的算法请看这里。你可以这样定义一个Action:
public void ExportExcel() { //生成Excel代码 }
然后输出Excel文件,这样做并不是很好,不利于单元测试。
而MVC框架非常容易扩展,我们只需要继承ActionResult,实现里面的方法:public override void ExecuteResult(ControllerContext context),和其它的ActionResult一样即可。实例代码如下:
1 public class ExcelResult<T> : ActionResult 2 { 3 public IEnumerable<T> SourceList { set; get; } 4 5 public DataTable SourceDataTable { set; get; } 6 7 public Dictionary<string, string> dic { set; get; } 8 9 public string FileName { set; get; } 10 11 public override void ExecuteResult(ControllerContext context) 12 { 13 //具体代码 14 } 15 }
我这里定义一个泛型类是为了处理不同类型的数据源。您还可以为T指定一个约束,比如:class。做完这些,还要为Controller添加相应的ExportExcel方法,这里我们就用到了扩展方法。具体代码如下:
1 public static class ControllerExtensions 2 { 3 /// <summary> 4 /// 生成Excel Will 5 /// </summary> 6 /// <typeparam name="T">数据源类型</typeparam> 7 /// <param name="source">数据源</param> 8 /// <returns></returns> 9 public static ExcelResult<T> ExcelExport<T>(this Controller controller, object source) 10 { 11 return ExcelExport<T>(controller, source, null, null); 12 } 13 /// <summary> 14 /// 生成Excel Will 15 /// </summary> 16 /// <typeparam name="T">数据源类型</typeparam> 17 /// <param name="source">数据源</param> 18 /// <param name="dic">要对应的Excel列头信息</param> 19 /// <returns></returns> 20 public static ExcelResult<T> ExcelExport<T>(this Controller controller, object source, Dictionary<string, string> dic) 21 { 22 return ExcelExport<T>(controller, source, dic, null); 23 } 24 25 /// <summary> 26 /// 生成Excel Will 27 /// </summary> 28 /// <typeparam name="T">数据源类型</typeparam> 29 /// <param name="source">数据源</param> 30 /// <param name="dic">要对应的Excel列头信息</param> 31 /// <param name="fileName">Excel名称</param> 32 /// <returns></returns> 33 public static ExcelResult<T> ExcelExport<T>(this Controller controller, object source, Dictionary<string, string> dic, string fileName) 34 { 35 var list = source as IEnumerable<T>; 36 var dt = source as DataTable; 37 return new ExcelResult<T>() 38 { 39 SourceDataTable = dt, 40 SourceList = list, 41 dic = dic, 42 FileName = fileName 43 }; 44 } 45 }
很简单,不是吗?
3、自定义错误处理类–HandleErrorAttribute
MVC中有一个错误处理类:HandleErrorAttribute,但是功能十分有限。我在项目里面扩展了一下,多出来的功能有:
1、增加错误日志记录并发送邮件提醒
2、增加对于AJAX错误的处理
3、暂时这么多了
代码示例如下:
1 public class HandleErrorExtensionsAttribute : HandleErrorAttribute 2 { 3 public override void OnException(ExceptionContext filterContext) 4 { 5 LogError(filterContext); 6 7 if (filterContext.HttpContext.Request.IsAjaxRequest()) 8 HandleAjaxError(filterContext); 9 else 10 base.OnException(filterContext); 11 } 12 13 /// <summary> 14 /// 记录错误日志 15 /// </summary> 16 /// <param name="filterContext"></param> 17 private void LogError(ExceptionContext filterContext) 18 { 19 ILog log = LogHelper.GetInstance(); 20 21 string errorMsg = string.Format("Controller: {0}|Action: {1}|id: {2}|Message: {3}|StackTrace:{4}", 22 filterContext.RouteData.Values["controller"], filterContext.RouteData.Values["action"], 23 filterContext.RouteData.Values["id"], filterContext.Exception.Message, filterContext.Exception.StackTrace); 24 25 log.AddLog(errorMsg, DateTime.Now); 26 } 27 28 /// <summary> 29 /// 处理Ajax请求的错误 30 /// </summary> 31 /// 多数代码来自MVC框架,只是将ActionResult改成json 32 /// <param name="filterContext"></param> 33 private void HandleAjaxError(ExceptionContext filterContext) 34 { 35 if (filterContext == null) 36 { 37 throw new ArgumentNullException("filterContext"); 38 } 39 40 // If custom errors are disabled, we need to let the normal ASP.NET exception handler 41 // execute so that the user can see useful debugging information. 42 if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) 43 { 44 return; 45 } 46 47 Exception exception = filterContext.Exception; 48 49 // If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method), 50 // ignore it. 51 if (new HttpException(null, exception).GetHttpCode() != 500) 52 { 53 return; 54 } 55 56 if (!ExceptionType.IsInstanceOfType(exception)) 57 { 58 return; 59 } 60 61 filterContext.Result = new JsonResult() { Data = string.Format("系统发送错误, {0}", filterContext.Exception.Message) }; 62 filterContext.ExceptionHandled = true; 63 filterContext.HttpContext.Response.Clear(); 64 filterContext.HttpContext.Response.StatusCode = 500; 65 66 // Certain versions of IIS will sometimes use their own error page when 67 // they detect a server error. Setting this property indicates that we 68 // want it to try to render ASP.NET MVC's error page instead. 69 filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 70 } 71 }
对于代码:filterContext.HttpContext.Request.IsAjaxRequest()是MVC提供的判断一个请求是不 是AJAX请求的方法,代码很简单,自己看一下就行了。之所以这样判断是因为现在的JavaScript类库在进行AJAX请求的时候都会在head里面 加入表示是AJAX请求的信息。
其余代码很清楚,就不多解释了。
一期的东西就写这么多暂时,MVC是一个很灵活,扩展性很好的框架,只要需要,你完全可以自定义很多东西。