介绍
asp.net mvc 之 Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test
- Action Filter - 在 Controller 层对信息做过滤。如何实现自定义的 Action Filter
- UpdateModel - 根据参数自动为对象的属性赋值
- ModelBinder - 定义如何绑定 Model,DefaultModelBinder 实现了 IModelBinder ,其可以根据名称自动将参数赋值到对象对应的属性上
- Ajax - 在 asp.net mvc 中使用 ajax
- Unit Test - 在 asp.net mvc 中使用单元测试
示例
1、asp.net mvc 自带的 Action Filter 的演示
FilterDemoController.cs
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Web.Mvc;
using
System.Web.Mvc.Ajax;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using
MVC.Models;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace
MVC.Controllers
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
// HandleError - 出现异常时跳转到 Error.aspx(先在指定的 view 文件夹找,找不到再在 Shared 文件夹下找)
// 需要 web.config 配置 - <customErrors mode="On" />
[HandleError]
public class FilterDemoController : Controller
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// 每一个 Filter 都有一个 Order 属性,其用来指定 Filter 的执行顺序
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// [NonAction] - 当前方法为普通方法,不解析为 Action
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// [AcceptVerbs(HttpVerbs)] - 调用该 Action 的 http 方法
// HttpVerbs 枚举成员如下: HttpVerbs.Get, HttpVerbs.Post, HttpVerbs.Put, HttpVerbs.Delete, HttpVerbs.Head
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
ProductSystem ps = new ProductSystem();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// ActionName() - Action 的名称。默认值同方法名称
[ActionName("Product")]
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// ValidateInput() - 相当于 @ Page 的 ValidateRequest, 用于验证请求中是否存在危险代码。可防止 XSS 攻击。默认值为 true
[ValidateInput(false)]
public ActionResult Details(int id)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
var product = ps.GetProduct(id);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return View("Details", product);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// ValidateAntiForgeryToken() - 避免 CSRF 攻击(需要视图页面中使用 Html.AntiForgeryToken())。原理:生成一个随机字符串,将其同时写入 cookie 和 hidden,当 form 提交到 action 时,验证二者是否相等并且验证提交源是否是本站页面(详查 asp.net mvc 的源代码)
// 拼 sql 的时候防止 sql 注入:使用 @Parameter 的方式
[ValidateAntiForgeryToken()]
public ActionResult ValidateAntiForgeryTokenTest()
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return Content("ValidateAntiForgeryToken");
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// OutputCache() - 缓存。Duration - 缓存秒数。VaryByParam - none, *, 多个参数用逗号隔开
[OutputCache(Duration = 10, VaryByParam = "none")]
// [OutputCache(CacheProfile = "MyCache")] - 通过配置文件对缓存做设置。可以参看 http://www.cnblogs.com/webabcd/archive/2007/02/15/651419.html
public ActionResult OutputCacheDemo()
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return Content(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public ActionResult HandleErrorDemo()
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
throw new Exception("HandleErrorDemo");
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// Authorize() - 验证。走的是 membership
[Authorize(Users = "user")]
// [Authorize(Roles = "role")]
// Request.IsAuthenticated - 返回一个 bool 值,用于指示请求是否通过了验证
public ActionResult AuthorizeDemo()
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return Content("Authorize");
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 自定义的 Action Filter 的 Demo
[MyFilter()]
public ActionResult MyFilterDemo()
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return Content("MyFilterDemo" + "<br />");
}
}
}
自定的 Action Filter 的实现
MyFilter.cs
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using
System.Web.Mvc;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace
MVC
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// 自定义的 Action Filter,需要继承 ActionFilterAttribute
/// </summary>
public class MyFilter : ActionFilterAttribute
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
HttpContext.Current.Response.Write("OnActionExecuting" + "<br />");
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public override void OnActionExecuted(ActionExecutedContext filterContext)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
HttpContext.Current.Response.Write("OnActionExecuted" + "<br />");
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public override void OnResultExecuting(ResultExecutingContext filterContext)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
HttpContext.Current.Response.Write("OnResultExecuting" + "<br />");
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public override void OnResultExecuted(ResultExecutedContext filterContext)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
HttpContext.Current.Response.Write("OnResultExecuted" + "<br />");
}
}
}
Details.aspx
<%
@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MVC.Models.Products>"
%>
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<
asp:Content
ID
="Content1"
ContentPlaceHolderID
="TitleContent"
runat
="server"
>
Details
</
asp:Content
>
<
asp:Content
ID
="Content2"
ContentPlaceHolderID
="MainContent"
runat
="server"
>
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<%
Html.BeginForm("ValidateAntiForgeryTokenTest", "FilterDemo");
%>
<%
=
Html.AntiForgeryToken()
%>
<
h2
>
Details
</
h2
>
<
p
>
<
strong
>
ProductID:
</
strong
>
<%
=
Html.Encode(Model.ProductID)
%>
</
p
>
<
p
>
<
strong
>
ProductName:
</
strong
>
<%
=
Html.Encode(Model.ProductName)
%>
</
p
>
<
p
>
<
input
type
="submit"
name
="btnSubmit"
value
="submit"
/>
</
p
>
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<%
Html.EndForm();
%>
</
asp:Content
>
2、应用 UpdateModel 的 Demo
UpdateModelController.cs
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Web.Mvc;
using
System.Web.Mvc.Ajax;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace
MVC.Controllers
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
public class UpdateModelController : Controller
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
public ActionResult Details(string name, int age)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
User user = new User();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// UpdateModel() 和 TryUpdateModel() - 系统根据参数自动为对象的属性赋值
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
base.UpdateModel(user); // 失败抛异常
// base.TryUpdateModel(user); // 失败不抛异常
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
ViewData.Model = user;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return View();
}
}
}
Details.aspx
<%
@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MVC.Controllers.User>"
%>
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<
asp:Content
ID
="Content1"
ContentPlaceHolderID
="TitleContent"
runat
="server"
>
Details
</
asp:Content
>
<
asp:Content
ID
="Content2"
ContentPlaceHolderID
="MainContent"
runat
="server"
>
<
h2
>
Details
</
h2
>
<
p
>
<
strong
>
UserId:
</
strong
>
<%
=
Model.ID
%>
</
p
>
<
p
>
<
strong
>
Name:
</
strong
>
<%
=
Model.Name
%>
</
p
>
<
p
>
<
strong
>
Age:
</
strong
>
<%
=
Model.Age
%>
</
p
>
</
asp:Content
>
3、演示什么是 ModelBinder
ModelBinderController.cs
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Web.Mvc;
using
System.Web.Mvc.Ajax;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace
MVC.Controllers
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
public class ModelBinderController : Controller
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// 路由过来的或者参数过来的,会自动地赋值到对象的对应的属性上
/// 做这个工作的就是实现了 IModelBinder 接口的 DefaultModelBinder
/// </summary>
public ActionResult Details(User user)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
base.ViewData.Model = user;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// ModelState - 保存 Model 的状态,包括相应的错误信息等
if (!base.ModelState.IsValid)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
foreach (var state in ModelState)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (!base.ModelState.IsValidField(state.Key))
ViewData["errorMsg"] = state.Key + "/" + state.Value.Value.AttemptedValue + "<br />";
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return View();
}
}
}
Details.aspx
<%
@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage"
%>
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<
asp:Content
ID
="Content1"
ContentPlaceHolderID
="TitleContent"
runat
="server"
>
Details
</
asp:Content
>
<
asp:Content
ID
="Content2"
ContentPlaceHolderID
="MainContent"
runat
="server"
>
<
h2
>
Details
</
h2
>
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<%
var model = ((MVC.Controllers.User)ViewData.Model);
%>
<
p
>
<
strong
>
UserId:
</
strong
>
<%
=
model.ID
%>
</
p
>
<
p
>
<
strong
>
Name:
</
strong
>
<%
=
model.Name
%>
</
p
>
<
p
>
<
strong
>
Age:
</
strong
>
<%
=
model.Age
%>
</
p
>
<
p
>
<
strong
>
error:
</
strong
>
<%
=
ViewData[
"
errorMsg
"
]
%>
</
p
>
</
asp:Content
>
4、使用 ajax 的 Demo
<
p
>
Ajax
<
script
src
="http://www.cnblogs.com/Scripts/MicrosoftAjax.debug.js"
type
="text/javascript"
></
script
>
<
script
src
="http://www.cnblogs.com/Scripts/MicrosoftMvcAjax.debug.js"
type
="text/javascript"
></
script
>
<
br
/>
<!--
AjaxHelper 简要说明
-->
<%
=
Ajax.ActionLink(
"
ProductId 为 1 的详情页
"
,
"
Details
"
,
"
Product
"
,
new
{ id
=
1
},
new
AjaxOptions { UpdateTargetId
=
"
ajax
"
}
)
%>
</
p
>
<
div
id
="ajax"
/>
5、在 VS 中做单元测试
ProductControllerTest.cs
using
MVC.Controllers;
using
Microsoft.VisualStudio.TestTools.UnitTesting;
using
Microsoft.VisualStudio.TestTools.UnitTesting.Web;
using
System.Web.Mvc;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using
MVC.Models;
using
System.Collections.Generic;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace
MVC.Tests
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
///这是 ProductControllerTest 的测试类,旨在
///包含所有 ProductControllerTest 单元测试
///</summary>
[TestClass()]
public class ProductControllerTest
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
private TestContext testContextInstance;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
///获取或设置测试上下文,上下文提供
///有关当前测试运行及其功能的信息。
///</summary>
public TestContext TestContext
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
get
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return testContextInstance;
}
set
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
testContextInstance = value;
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
附加测试属性#region 附加测试属性
//
//编写测试时,还可使用以下属性:
//
//使用 ClassInitialize 在运行类中的第一个测试前先运行代码
//[ClassInitialize()]
//public static void MyClassInitialize(TestContext testContext)
//{
//}
//
//使用 ClassCleanup 在运行完类中的所有测试后再运行代码
//[ClassCleanup()]
//public static void MyClassCleanup()
//{
//}
//
//使用 TestInitialize 在运行每个测试前先运行代码
//[TestInitialize()]
//public void MyTestInitialize()
//{
//}
//
//使用 TestCleanup 在运行完每个测试后运行代码
//[TestCleanup()]
//public void MyTestCleanup()
//{
//}
//
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
///Index 的测试
///</summary>
// TODO: 确保 UrlToTest 属性指定一个指向 ASP.NET 页的 URL(例如,
// http://
/Default.aspx)。这对于在 Web 服务器上执行单元测试是必需的,
//无论要测试页、Web 服务还是 WCF 服务都是如此。
[TestMethod()]
[HostType("ASP.NET")]
[AspNetDevelopmentServerHost("C:\\MVC\\MVC", "/")]
[UrlToTest("http://localhost:2005/")]
public void IndexTest()
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
ProductController target = new ProductController(); // TODO: 初始化为适当的值
int pageIndex = 0; // TODO: 初始化为适当的值
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
ViewResult actual;
actual = target.Index(pageIndex) as ViewResult;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
Assert.AreNotEqual(actual.ViewData.Model as List<Products>, null);
}
}
}