10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
<h1>Microsoft Ajax方式</h1>
@using (Ajax.BeginForm("GetServerDate","Home",new AjaxOptions()
HttpMethod = "POST",
Confirm = "您确定要提交?",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "spResult",
OnSuccess = "afterSuccess",
LoadingElementId="loading"
}))
{
<table>
<tr>
<td>
<input id="txtUserName" name="UserName" /></td>
</tr>
<tr>
<td>密 码:</td>
<td>
<input id="txtPassword" name="Password" /></td>
</tr>
<tr>
<td align="center" colspan="2">
<input id="btnAjax" type="submit" value="提 交" />
</td>
</tr>
<tr>
<td align="center" colspan="2">
<div id="loading" style="display:none">
<img style="vertical-align:middle" src="~/Content/ico_loading2.gif" />正在获取中,请稍候...
</div>
<span id="spResult"></span>
</td>
</tr>
</table>
这里需要注意的是:
①Ajax.BeginForm没有提供闭合的方法,需要使用Using配合关闭;
②AjaxOptions参数的设置:
HttpMethod代表此次AJAX请求到底是POST方式还是GET方式?这里是POST方式;
Confirm代表点击提交按钮后提出的确认对话框,并给出用户给定的提示语,这里是:您确定要提交?
InsertionMode代表请求获得后的数据是要替换还是追加,一般选择替换,即Replace;
UpdateTargetId代表需要替换的div标签的Id,这里是一个span标签,代表需要显示的信息都显示在这个span内;
OnSuccess代表请求成功后所需要执行的回调方法,是一个js方法,可以自定义,这里是一个function afterSuccess()的方法;
function afterSuccess(data) {
//alert("您已成功获取数据:" + data);
LoadingElementId=”loading”是一个很有意思的属性,代表在ajax请求期间为了提供良好的用户体验,可以给出一个正在加载中的提示,而这个LoadingElementId则代表一个提示的div区域的Id。这里主要是指id为loading的这个div,其中有一张gif图片及一句话:正在获取中,请稍等…的提示。
3
|
<div id="loading" style="display:none">
<img style="vertical-align:middle" src="~/Content/ico_loading2.gif" />正在获取中,请稍候...
</div>
|
为了显示加载提示的效果,我们人为地修改一下Action方法,使用Thread.Sleep(3000)来延迟一下请求返回时间
System.Threading.Thread.Sleep(3000);
return Content(DateTime.Now.ToString());
好了,现在我们可以看一下效果如何:
到此,我们的Microsoft AJAX就算完成了一个最简单的Demo了。那么,我们不禁想知道Microsoft AJAX是怎么做到的?跟校验一样,我们浏览一下生成的form表单就知道了:
原来我们在AjaxOptions中所设置的参数也被解析成了form的自定义属性,它们的对应关系如下:
三、为AOP而生 — ASP.Net MVC默认的过滤器
3.1 过滤器初步
大一点的项目总会有相关的AOP面向切面的组件,而MVC(特指:Asp.Net MVC,以下皆同)项目中Action在执行前或者执行后我们想做一些特殊的操作(比如身份验证,日志,异常,行为 截取等),而不想让MVC开发人员去关心和写这部分重复的 代码。那么,我们可以通过AOP 截取实现,而在MVC项目中我们就可以直接使用它提供的Filter的特性帮我们 解决,不用自己实现复杂的AOP了。
AOP:Aspect Oriented Programming(AOP)是较为热门的一个话题。AOP,国内大致译作“面向切面编程”。针对业务处理过程中的切面进行 提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离 效果。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。主要的 功能是:日志记录, 性能统计,安全控制,事务处理,异常处理等等。
3.2 微软提供的几种默认过滤器
微软默认为我们提供了四种类型的过滤器(Filter),如下图所示:
这里,我们主要来看看ActionFilter(Action过滤器)和ExceptionFilter(异常过滤器)的使用:
(1)Action Filter
ActionFilterAttribute默认实现了IActionFilter和IResultFilter。而ActionFilterAttribute是一个Abstract的类型,所以不能直接使用,因为它不能实例化,所以我们想使用它必须继承一下它然后才能使用。
①因此,我们首先在Models中新建一个类,取名为:MyActionFilterAttribute(以Attribute结尾比较符合编码规范),并使其继承自ActionFilterAttribute,然后重写基类所提供的虚方法:
37
38
39
40
41
42
43
44
45
|
public class MyActionFilterAttribute : ActionFilterAttribute
public string Name { get; set; }
/// <summary>
/// </summary>
/// <param name="filterContext">过滤器上下文</param>
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
HttpContext.Current.Response.Write("OnActionExecuting :" + Name);
}
/// <summary>
/// Action执行之后
/// </summary>
/// <param name="filterContext">过滤器上下文</param>
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
HttpContext.Current.Response.Write("OnActionExecuted :" + Name);
}
/// <summary>
/// ActionResult执行之前先执行此方法
/// </summary>
/// <param name="filterContext">过滤器上下文</param>
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
base.OnResultExecuting(filterContext);
HttpContext.Current.Response.Write("OnResultExecuting :" + Name);
}
/// <summary>
/// ActionResult执行之后先执行此方法
/// </summary>
/// <param name="filterContext">过滤器上下文</param>
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
base.OnResultExecuted(filterContext);
HttpContext.Current.Response.Write("OnResultExecuted :" + Name);
}
这里我们重写了四个虚方法,他们各自代表了在Action执行之前和之后需要执行的业务逻辑,以及在Result执行之前和之后需要执行的业务逻辑。这里的Result主要是指我们在Action中进行return 语句返回结果时(例如:return Content(“Hello Filter!”);),之前和之后要执行的逻辑处理。
比如:我们想要在每个Action执行之前进行用户是否登录的校验,可以在OnActionExecuting中判断用户Session是否存在,如果存在则继续执行Action的具体业务代码,如果不存在则重定向页面到登陆页,后边的Action业务代码不再执行。
②现在有了自定义的过滤器,我们怎么将其应用到Action中呢?这里有三种方式:
一是给某个控制器的某个Action指定此Filter:
[MyActionFilter(Name = "Filter Action")]
public ActionResult Filter()
Response.Write("<p>Action正在努力执行中...</p>");
return Content("<p>OK:视图成功被渲染</p>");
二是给某个控制器的所有Action指定此Filter:
[MyActionFilter(Name="Home Filter")]
public class HomeController : Controller
{
但是,要注意的是:如果既给Controller指定了Filter,又给该Controller中的某个Action指定了Filter,那么具体的这个Action以离其定义最近的Filter为准,也就是一个优先级的顺序问题:Action的Filter优先级高于Controller的Filter。
三是给此项目中的所有控制器即全局指定此Filter:在App_Start中更改FilterConfig类,此种方式优先级最低。
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
filters.Add(new HandleErrorAttribute());
// 注册自定义Action过滤器:优先级最低,但是可以作用到所有的控制器和Action
filters.Add(new MyActionFilterAttribute() { Name = "Global Controller" });
③现在我们来看看具体的效果:
可以看到,我们的/Home/Filter这个Action中只有两句代码,一句Response.Write,另一句是return Content();在Response.Write之前执行了OnActionExecuting的过滤器方法,之后则执行了OnActionExecuted的过滤器方法;我们刚刚说了,在Action中的return语句代表了Result,那么在Result之前执行了OnResultExecuting过滤器方法,之后则执行了OnResultExecuted过滤器方法。这里仅仅是为了展示,在实际开发中是需要写一些具体的业务逻辑处理的,例如:判断用户的登录状态,记录用户的操作日志等等。
(2)Exception Filter
①同样,在Models中新建一个类,取名为:MyExceptionFilterAttribute,并使其继承自HandleErrorAttribute。
public class MyExceptionFilterAttribute : HandleErrorAttribute
public override void OnException(ExceptionContext filterContext)
{
base.OnException(filterContext);
HttpContext.Current.Response.Redirect("/Home/Index");
}
这里,重写基类的OnException方法,这里仅仅为了演示效果,没有对异常进行处理。在实际开发中,需要获取异常对象,并将其记录至日志中。例如,下面一段代码:
|
public override void OnException(ExceptionContext filterContext)
base.OnException(filterContext);
string strException = filterContext.Exception.Message;
if (!string.IsNullOrEmpty(strException))
{
//使用Log4Net记录异常信息
Exception exception = filterContext.Exception;
if (exception != null)
LogHelper.WriteErrorLog(strException,exception);
}
else
{
LogHelper.WriteErrorLog(strException);
}
}
filterContext.HttpContext.Response.Redirect("~/GlobalErrorPage.html");
②有了异常过滤器,我们怎么来应用到项目中呢?答案也在App_Start中,还是在FilterConfig类中,新添一句代码进行注册:
|
public class FilterConfig
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
filters.Add(new HandleErrorAttribute());
// 注册自定义Action过滤器:优先级最低,但是可以作用到所有的控制器和Action
filters.Add(new MyActionFilterAttribute() { Name = "Global Controller" });
filters.Add(new MyExceptionFilterAttribute());
}
③为了测试,我们新增一个Action,使其能够出现一个异常:DividedByZero
public ActionResult Exception()
int a = 10;
int b = 0;
int c = a / b;
return Content("Exception is happened.");
④当我们测试这个Action时,会发现系统执行了自定义的异常过滤器,将我们的这个请求改为重定向到Index这个Action了。
参考资料
(1)蒋金楠,《ASP.NET MVC下的四种验证编程方式》,http://www.cnblogs.com/artech/p/asp-net-mvc-validation-programming.html
(2)蒋金楠,《ASP.NET MVC下的四种验证编程方式[续篇]》,http://www.cnblogs.com/artech/p/asp-net-mvc-4-validation.html
(3)马伦,《ASP.NET MVC 2014特供教程》,http://bbs.itcast.cn/thread-26722-1-1.html
(4)w809026418,《MVC中使用 DataAnnotations 进行模型验证》,http://www.cnblogs.com/haogj/archive/2011/11/16/2251920.html
(5)刘俊峰,《ASP.NET MVC中Unobtrusive Ajax的妙用》,http://www.cnblogs.com/rufi/archive/2012/03/31/unobtrusive-ajax.html
|