asp.net mvc 1.0,5 - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test

介绍

  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)]

        public 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()]

        public 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

        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 的实现

  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 ContentPlaceHolder runat="server">

    Details

</asp:Content>

<asp:Content ContentPlaceHolder 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、应用 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() - 系统根据参数自动为对象的属性赋值

            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 ContentPlaceHolder runat="server">

    Details

</asp:Content>

<asp:Content ContentPlaceHolder 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>

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

        /// 做这个                }

            }

            return View();

        }

    }

}

Details.aspx

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

<asp:Content ContentPlaceHolder runat="server">

    Details

</asp:Content>

<asp:Content ContentPlaceHolder 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.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 />

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>

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

        ///有关当前测试运行及其        public 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);

        }

    }

}