迭戈

博客园 首页 新随笔 联系 管理

摘要:本人用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一样即可。实例代码如下:

ExcelResult
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方法,这里我们就用到了扩展方法。具体代码如下:

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、暂时这么多了

代码示例如下:

HandleErrorExtensionsAttribute
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是一个很灵活,扩展性很好的框架,只要需要,你完全可以自定义很多东西。

posted on 2011-02-22 16:19  Will Meng  阅读(3354)  评论(5编辑  收藏  举报