返璞歸真 asp.net mvc (5) - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test
[索引頁]
[源碼下載]
作者:webabcd
介紹
asp.net mvc 之 Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test
示例
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;

using MVC.Models;

namespace MVC.Controllers
{
// HandleError - 出現(xiàn)異常時跳轉(zhuǎn)到 Error.aspx(先在指定的 view 文件夾找,找不到再在 Shared 文件夾下找)
// 需要 web.config 配置 - <customErrors mode="On" />
[HandleError]
public class FilterDemoController : Controller
{
// 每一個 Filter 都有一個 Order 屬性,其用來指定 Filter 的執(zhí)行順序

// [NonAction] - 當(dāng)前方法為普通方法,不解析為 Action

// [AcceptVerbs(HttpVerbs)] - 調(diào)用該 Action 的 http 方法
// HttpVerbs 枚舉成員如下: HttpVerbs.Get, HttpVerbs.Post, HttpVerbs.Put, HttpVerbs.Delete, HttpVerbs.Head


ProductSystem ps = new ProductSystem();


// ActionName() - Action 的名稱。默認(rèn)值同方法名稱
[ActionName("Product")]

// ValidateInput() - 相當(dāng)于 @ Page 的 ValidateRequest, 用于驗證請求中是否存在危險代碼。可防止 XSS 攻擊。默認(rèn)值為 true
[ValidateInput(false)]
public ActionResult Details(int id)
{
var product = ps.GetProduct(id);

return View("Details", product);
}

// ValidateAntiForgeryToken() - 避免 CSRF 攻擊(需要視圖頁面中使用 Html.AntiForgeryToken())。原理:生成一個隨機字符串,將其同時寫入 cookie 和 hidden,當(dāng) form 提交到 action 時,驗證二者是否相等并且驗證提交源是否是本站頁面(詳查 asp.net mvc 的源代碼)
// 拼 sql 的時候防止 sql 注入:使用 @Parameter 的方式
[ValidateAntiForgeryToken()]
public ActionResult ValidateAntiForgeryTokenTest()
{
return Content("ValidateAntiForgeryToken");
}

// OutputCache() - 緩存。Duration - 緩存秒數(shù)。VaryByParam - none, *, 多個參數(shù)用逗號隔開
[OutputCache(Duration = 10, VaryByParam = "none")]
// [OutputCache(CacheProfile = "MyCache")] - 通過配置文件對緩存做設(shè)置。可以參看 http://www.rzrgm.cn/webabcd/archive/2007/02/15/651419.html
public ActionResult OutputCacheDemo()
{
return Content(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
}

public ActionResult HandleErrorDemo()
{
throw new Exception("HandleErrorDemo");
}

// Authorize() - 驗證。走的是 membership
[Authorize(Users = "user")]
// [Authorize(Roles = "role")]
// Request.IsAuthenticated - 返回一個 bool 值,用于指示請求是否通過了驗證
public ActionResult AuthorizeDemo()
{
return Content("Authorize");
}

// 自定義的 Action Filter 的 Demo
[MyFilter()]
public ActionResult MyFilterDemo()
{
return Content("MyFilterDemo" + "<br />");
}
}
}
自定的 Action Filter 的實現(xiàn)
MyFilter.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Web.Mvc;

namespace MVC
{
/// <summary>
/// 自定義的 Action Filter,需要繼承 ActionFilterAttribute
/// </summary>
public class MyFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext.Current.Response.Write("OnActionExecuting" + "<br />");
}

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
HttpContext.Current.Response.Write("OnActionExecuted" + "<br />");
}

public override void OnResultExecuting(ResultExecutingContext filterContext)
{
HttpContext.Current.Response.Write("OnResultExecuting" + "<br />");
}

public override void OnResultExecuted(ResultExecutedContext filterContext)
{
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>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Details
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% 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>
<% Html.EndForm(); %>
</asp:Content>
2、應(yīng)用 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;

namespace MVC.Controllers
{
public class UpdateModelController : Controller
{
public ActionResult Details(string name, int age)
{
User user = new User();

// UpdateModel() 和 TryUpdateModel() - 系統(tǒng)根據(jù)參數(shù)自動為對象的屬性賦值

base.UpdateModel(user); // 失敗拋異常
// base.TryUpdateModel(user); // 失敗不拋異常

ViewData.Model = user;

return View();
}
}
}
Details.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MVC.Controllers.User>" %>

<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;

namespace MVC.Controllers
{
public class ModelBinderController : Controller
{
/// <summary>
/// 路由過來的或者參數(shù)過來的,會自動地賦值到對象的對應(yīng)的屬性上
/// 做這個工作的就是實現(xiàn)了 IModelBinder 接口的 DefaultModelBinder
/// </summary>
public ActionResult Details(User user)
{
base.ViewData.Model = user;

// ModelState - 保存 Model 的狀態(tài),包括相應(yīng)的錯誤信息等
if (!base.ModelState.IsValid)
{
foreach (var state in ModelState)
{
if (!base.ModelState.IsValidField(state.Key))
ViewData["errorMsg"] = state.Key + "/" + state.Value.Value.AttemptedValue + "<br />";
}
}

return View();
}
}
}
Details.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Details
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>
Details</h2>
<% 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.rzrgm.cn/Scripts/MicrosoftAjax.debug.js" type="text/javascript"></script>
<script src="http://www.rzrgm.cn/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;

using MVC.Models;
using System.Collections.Generic;

namespace MVC.Tests
{
/// <summary>
///這是 ProductControllerTest 的測試類,旨在
///包含所有 ProductControllerTest 單元測試
///</summary>
[TestClass()]
public class ProductControllerTest
{
private TestContext testContextInstance;

/// <summary>
///獲取或設(shè)置測試上下文,上下文提供
///有關(guān)當(dāng)前測試運行及其功能的信息。
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}

附加測試屬性


/// <summary>
///Index 的測試
///</summary>
// TODO: 確保 UrlToTest 屬性指定一個指向 ASP.NET 頁的 URL(例如,
// http://
/Default.aspx)。這對于在 Web 服務(wù)器上執(zhí)行單元測試是必需的,
//無論要測試頁、Web 服務(wù)還是 WCF 服務(wù)都是如此。
[TestMethod()]
[HostType("ASP.NET")]
[AspNetDevelopmentServerHost("C:\\MVC\\MVC", "/")]
[UrlToTest("http://localhost:2005/")]
public void IndexTest()
{
ProductController target = new ProductController(); // TODO: 初始化為適當(dāng)?shù)闹?/span>
int pageIndex = 0; // TODO: 初始化為適當(dāng)?shù)闹?/span>

ViewResult actual;
actual = target.Index(pageIndex) as ViewResult;

Assert.AreNotEqual(actual.ViewData.Model as List<Products>, null);
}
}
}
OK
[源碼下載]
[源碼下載]
返璞歸真 asp.net mvc (5) - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test
作者:webabcd
介紹
asp.net mvc 之 Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test
- Action Filter - 在 Controller 層對信息做過濾。如何實現(xiàn)自定義的 Action Filter
- UpdateModel - 根據(jù)參數(shù)自動為對象的屬性賦值
- ModelBinder - 定義如何綁定 Model,DefaultModelBinder 實現(xiàn)了 IModelBinder ,其可以根據(jù)名稱自動將參數(shù)賦值到對象對應(yīng)的屬性上
- 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;
using MVC.Models;
namespace MVC.Controllers
{
// HandleError - 出現(xiàn)異常時跳轉(zhuǎn)到 Error.aspx(先在指定的 view 文件夾找,找不到再在 Shared 文件夾下找)
// 需要 web.config 配置 - <customErrors mode="On" />
[HandleError]
public class FilterDemoController : Controller
{
// 每一個 Filter 都有一個 Order 屬性,其用來指定 Filter 的執(zhí)行順序
// [NonAction] - 當(dāng)前方法為普通方法,不解析為 Action
// [AcceptVerbs(HttpVerbs)] - 調(diào)用該 Action 的 http 方法
// HttpVerbs 枚舉成員如下: HttpVerbs.Get, HttpVerbs.Post, HttpVerbs.Put, HttpVerbs.Delete, HttpVerbs.Head

ProductSystem ps = new ProductSystem();

// ActionName() - Action 的名稱。默認(rèn)值同方法名稱
[ActionName("Product")]
// ValidateInput() - 相當(dāng)于 @ Page 的 ValidateRequest, 用于驗證請求中是否存在危險代碼。可防止 XSS 攻擊。默認(rèn)值為 true
[ValidateInput(false)]
public ActionResult Details(int id)
{
var product = ps.GetProduct(id);
return View("Details", product);
}
// ValidateAntiForgeryToken() - 避免 CSRF 攻擊(需要視圖頁面中使用 Html.AntiForgeryToken())。原理:生成一個隨機字符串,將其同時寫入 cookie 和 hidden,當(dāng) form 提交到 action 時,驗證二者是否相等并且驗證提交源是否是本站頁面(詳查 asp.net mvc 的源代碼)
// 拼 sql 的時候防止 sql 注入:使用 @Parameter 的方式
[ValidateAntiForgeryToken()]
public ActionResult ValidateAntiForgeryTokenTest()
{
return Content("ValidateAntiForgeryToken");
}
// OutputCache() - 緩存。Duration - 緩存秒數(shù)。VaryByParam - none, *, 多個參數(shù)用逗號隔開
[OutputCache(Duration = 10, VaryByParam = "none")]
// [OutputCache(CacheProfile = "MyCache")] - 通過配置文件對緩存做設(shè)置。可以參看 http://www.rzrgm.cn/webabcd/archive/2007/02/15/651419.html
public ActionResult OutputCacheDemo()
{
return Content(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
}
public ActionResult HandleErrorDemo()
{
throw new Exception("HandleErrorDemo");
}
// Authorize() - 驗證。走的是 membership
[Authorize(Users = "user")]
// [Authorize(Roles = "role")]
// Request.IsAuthenticated - 返回一個 bool 值,用于指示請求是否通過了驗證
public ActionResult AuthorizeDemo()
{
return Content("Authorize");
}
// 自定義的 Action Filter 的 Demo
[MyFilter()]
public ActionResult MyFilterDemo()
{
return Content("MyFilterDemo" + "<br />");
}
}
}
自定的 Action Filter 的實現(xiàn)
MyFilter.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVC
{
/// <summary>
/// 自定義的 Action Filter,需要繼承 ActionFilterAttribute
/// </summary>
public class MyFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext.Current.Response.Write("OnActionExecuting" + "<br />");
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
HttpContext.Current.Response.Write("OnActionExecuted" + "<br />");
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
HttpContext.Current.Response.Write("OnResultExecuting" + "<br />");
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
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>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Details
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% 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>
<% Html.EndForm(); %>
</asp:Content>
2、應(yīng)用 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;
namespace MVC.Controllers
{
public class UpdateModelController : Controller
{
public ActionResult Details(string name, int age)
{
User user = new User();
// UpdateModel() 和 TryUpdateModel() - 系統(tǒng)根據(jù)參數(shù)自動為對象的屬性賦值
base.UpdateModel(user); // 失敗拋異常
// base.TryUpdateModel(user); // 失敗不拋異常
ViewData.Model = user;
return View();
}
}
}
Details.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MVC.Controllers.User>" %>
<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;
namespace MVC.Controllers
{
public class ModelBinderController : Controller
{
/// <summary>
/// 路由過來的或者參數(shù)過來的,會自動地賦值到對象的對應(yīng)的屬性上
/// 做這個工作的就是實現(xiàn)了 IModelBinder 接口的 DefaultModelBinder
/// </summary>
public ActionResult Details(User user)
{
base.ViewData.Model = user;
// ModelState - 保存 Model 的狀態(tài),包括相應(yīng)的錯誤信息等
if (!base.ModelState.IsValid)
{
foreach (var state in ModelState)
{
if (!base.ModelState.IsValidField(state.Key))
ViewData["errorMsg"] = state.Key + "/" + state.Value.Value.AttemptedValue + "<br />";
}
}
return View();
}
}
}
Details.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Details
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>
Details</h2>
<% 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.rzrgm.cn/Scripts/MicrosoftAjax.debug.js" type="text/javascript"></script>
<script src="http://www.rzrgm.cn/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;
using MVC.Models;
using System.Collections.Generic;
namespace MVC.Tests
{
/// <summary>
///這是 ProductControllerTest 的測試類,旨在
///包含所有 ProductControllerTest 單元測試
///</summary>
[TestClass()]
public class ProductControllerTest
{
private TestContext testContextInstance;
/// <summary>
///獲取或設(shè)置測試上下文,上下文提供
///有關(guān)當(dāng)前測試運行及其功能的信息。
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
附加測試屬性

/// <summary>
///Index 的測試
///</summary>
// TODO: 確保 UrlToTest 屬性指定一個指向 ASP.NET 頁的 URL(例如,
// http://
/Default.aspx)。這對于在 Web 服務(wù)器上執(zhí)行單元測試是必需的,
//無論要測試頁、Web 服務(wù)還是 WCF 服務(wù)都是如此。
[TestMethod()]
[HostType("ASP.NET")]
[AspNetDevelopmentServerHost("C:\\MVC\\MVC", "/")]
[UrlToTest("http://localhost:2005/")]
public void IndexTest()
{
ProductController target = new ProductController(); // TODO: 初始化為適當(dāng)?shù)闹?/span>
int pageIndex = 0; // TODO: 初始化為適當(dāng)?shù)闹?/span>
ViewResult actual;
actual = target.Index(pageIndex) as ViewResult;
Assert.AreNotEqual(actual.ViewData.Model as List<Products>, null);
}
}
}
OK
[源碼下載]

浙公網(wǎng)安備 33010602011771號