天天看点

返璞归真 asp.net mvc (5) - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test

[索引页]

[×××]

返璞归真 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 层对信息做过滤。如何实现自定义的 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;

using MVC.Models;

namespace MVC.Controllers

{

        // HandleError - 出现异常时跳转到 Error.aspx(先在指定的 view 文件夹找,找不到再在 Shared 文件夹下找)

        // 需要 web.config 配置 - <customErrors mode="On" />

        [HandleError]

        public class FilterDemoController : Controller

        {

                // 每一个 Filter 都有一个 Order 属性,其用来指定 Filter 的执行顺序

                // [NonAction] - 当前方法为普通方法,不解析为 Action

                // [AcceptVerbs(HttpVerbs)] - 调用该 Action 的 http 方法

                // HttpVerbs 枚举成员如下: HttpVerbs.Get, HttpVerbs.Post, HttpVerbs.Put, HttpVerbs.Delete, HttpVerbs.Head

                ProductSystem ps = new ProductSystem();

                // ActionName() - Action 的名称。默认值同方法名称

                [ActionName("Product")]

                // ValidateInput() - 相当于 @ Page 的 ValidateRequest, 用于验证请求中是否存在危险代码。可防止 XSS 攻击。默认值为 true

                [ValidateInput(false)]

ActionResult Details() ActionResult Details(int id)

                {

                        var product = ps.GetProduct(id);

                        return View("Details", product);

                }

                // ValidateAntiForgeryToken() - 避免 CSRF 攻击(需要视图页面中使用 Html.AntiForgeryToken())。原理:生成一个随机字符串,将其同时写入 cookie 和 hidden,当 form 提交到 action 时,验证二者是否相等并且验证提交源是否是本站页面(详查 asp.net mvc 的源代码)

                // 拼 sql 的时候防止 sql 注入:使用 @Parameter 的方式

                [ValidateAntiForgeryToken()]

ActionResult ValidateAntiForgeryTokenTest() ActionResult ValidateAntiForgeryTokenTest()

                        return Content("ValidateAntiForgeryToken");

                // OutputCache() - 缓存。Duration - 缓存秒数。VaryByParam - none, *, 多个参数用逗号隔开

                [OutputCache(Duration = 10, VaryByParam = "none")]

                // [OutputCache(CacheProfile = "MyCache")] - 通过配置文件对缓存做设置。可以参看 http://www.cnblogs.com/webabcd/archive/2007/02/15/651419.html

ActionResult OutputCacheDemo() ActionResult OutputCacheDemo()

                        return Content(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));

ActionResult HandleErrorDemo() ActionResult HandleErrorDemo()

                        throw new Exception("HandleErrorDemo");

                // Authorize() - 验证。走的是 membership

                [Authorize(Users = "user")]

                // [Authorize(Roles = "role")]

                // Request.IsAuthenticated - 返回一个 bool 值,用于指示请求是否通过了验证

ActionResult AuthorizeDemo() ActionResult AuthorizeDemo()

                        return Content("Authorize");

                // 自定义的 Action Filter 的 Demo

                [MyFilter()]

ActionResult MyFilterDemo() ActionResult MyFilterDemo()

                        return Content("MyFilterDemo" + "<br />");

        }

}

自定的 Action Filter 的实现

MyFilter.cs

namespace MVC

        /**//// <summary>

        /// 自定义的 Action Filter,需要继承 ActionFilterAttribute

        /// </summary>

        public class MyFilter : ActionFilterAttribute

override void OnActionExecuting() override void OnActionExecuting(ActionExecutingContext filterContext)

                        HttpContext.Current.Response.Write("OnActionExecuting" + "<br />");

override void OnActionExecuted() override void OnActionExecuted(ActionExecutedContext filterContext)

                        HttpContext.Current.Response.Write("OnActionExecuted" + "<br />");

override void OnResultExecuting() override void OnResultExecuting(ResultExecutingContext filterContext)

                        HttpContext.Current.Response.Write("OnResultExecuting" + "<br />");

override void OnResultExecuted() 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>

                <strong>ProductName:</strong>

                <%= Html.Encode(Model.ProductName) %>

                <input type="submit" name="btnSubmit" value="submit" />

        <% Html.EndForm(); %>

2、应用 UpdateModel 的 Demo

UpdateModelController.cs

        public class UpdateModelController : Controller

ActionResult Details() ActionResult Details(string name, int age)

                        User user = new User();

                        // UpdateModel() 和 TryUpdateModel() - 系统根据参数自动为对象的属性赋值

                        base.UpdateModel(user); // 失败抛异常

                        // base.TryUpdateModel(user); // 失败不抛异常

                        ViewData.Model = user;

                        return View();

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MVC.Controllers.User>" %>

                <strong>UserId:</strong>

                <%= Model.ID %>

                <strong>Name:</strong>

                <%= Model.Name%>

                <strong>Age:</strong>

                <%= Model.Age%>

3、演示什么是 ModelBinder

ModelBinderController.cs

        public class ModelBinderController : Controller

                /**//// <summary>

                /// 路由过来的或者参数过来的,会自动地赋值到对象的对应的属性上

                /// 做这个工作的就是实现了 IModelBinder 接口的 DefaultModelBinder

                /// </summary>

ActionResult Details() ActionResult Details(User user)

                        base.ViewData.Model = user;

                        // ModelState - 保存 Model 的状态,包括相应的错误信息等

                        if (!base.ModelState.IsValid)

                        {

                                foreach (var state in ModelState)

                                {

                                        if (!base.ModelState.IsValidField(state.Key))

                                                ViewData["errorMsg"] = state.Key + "/" + state.Value.Value.AttemptedValue + "<br />";

                                }

                        }

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

        <% var model = ((MVC.Controllers.User)ViewData.Model); %>

                <%= model.ID %>

                <%= model.Name %>

                <%= model.Age %>

                <strong>error:</strong>

                <%= ViewData["errorMsg"] %>

4、使用 ajax 的 Demo

                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" }

                        )

                %>    

        <div id="ajax" />

5、在 VS 中做单元测试

ProductControllerTest.cs

using MVC.Controllers;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using Microsoft.VisualStudio.TestTools.UnitTesting.Web;

namespace MVC.Tests

        ///这是 ProductControllerTest 的测试类,旨在

        ///包含所有 ProductControllerTest 单元测试

        ///</summary>

        [TestClass()]

        public class ProductControllerTest

                private TestContext testContextInstance;

                ///获取或设置测试上下文,上下文提供

                ///有关当前测试运行及其功能的信息。

                ///</summary>

                public TestContext TestContext

                        get

                                return testContextInstance;

                        set

                                testContextInstance = value;

附加测试属性#region 附加测试属性

                //    

                //编写测试时,还可使用以下属性:

                //

                //使用 ClassInitialize 在运行类中的第一个测试前先运行代码

                //[ClassInitialize()]

static void MyClassInitialize() static void MyClassInitialize(TestContext testContext)

                //{

                //}

                //使用 ClassCleanup 在运行完类中的所有测试后再运行代码

                //[ClassCleanup()]

static void MyClassCleanup() static void MyClassCleanup()

                //使用 TestInitialize 在运行每个测试前先运行代码

                //[TestInitialize()]

void MyTestInitialize() void MyTestInitialize()

                //使用 TestCleanup 在运行完每个测试后运行代码

                //[TestCleanup()]

void MyTestCleanup() void MyTestCleanup()

                #endregion

                ///Index 的测试

                // TODO: 确保 UrlToTest 属性指定一个指向 ASP.NET 页的 URL(例如,

                // http:///Default.aspx)。这对于在 Web 服务器上执行单元测试是必需的,

                //无论要测试页、Web 服务还是 WCF 服务都是如此。

                [TestMethod()]

                [HostType("ASP.NET")]

                [AspNetDevelopmentServerHost("C:\\MVC\\MVC", "/")]

                [UrlToTest("http://localhost:2005/")]

void IndexTest() void IndexTest()

                        ProductController target = new ProductController(); // TODO: 初始化为适当的值

                        int pageIndex = 0; // TODO: 初始化为适当的值

                        ViewResult actual;

                        actual = target.Index(pageIndex) as ViewResult;

                        Assert.AreNotEqual(actual.ViewData.Model as List<Products>, null);

OK

继续阅读