1、為 Action 標注 Attribute 限制訪問
public class HomeController : Controller { [HttpPost] public ActionResult Index() { return View(); } }
那么該 Index 的 Action 就只能夠通過 Post 方法請求,其它例如 Get 方法請求則響應 404。
2、設置 View 所使用的 Model
假設有 Person 類。
則 Controll 代碼:
public class HomeController : Controller { public ActionResult Index() { var model = new Person();// 構建或從數據庫獲取一個 Person 類實例。 return View(model); } }
或者可以設置 ViewData 的 Model 屬性。
public class HomeController : Controller { public ActionResult Index() { var model = new Person(); ViewData.Model = model; return View(); } }
View 代碼:
@* 聲明該 View 的 Model 類型 *@
@model Namespace.Person
……
@* 輸出 Person 對象的 Name 屬性 *@
@Model.Name
……
當然不聲明 View 的 Model 類型也是可以的,但是這會失去 Model 類型約束以及語法提示等功能。
在聲明了 Model 類型的情況下,View 繼承自 WebViewPage<TModel> 抽象類。
而不聲明 Model 類型的情況下,View 則繼承自 WebViewPage<dynamic> 抽象類。
3、Model 驗證
修改 Person 類,添加相應的 ValidationAttribute
public class Person { [Required] [StringLength(5)] public string Name { get; set; } [Range(0, 150)] public int Age { get; set; } [Required] [EmailAddress] [DataType(DataType.EmailAddress)] public string Email { get; set; } }
Controller 驗證:
public class HomeController : Controller { [HttpPost] public ActionResult Create(Person person) { if (ModelState.IsValid) { return Content("驗證成功"); } else { return Content("驗證失敗"); } } }
View 中的客戶端驗證:
<body> @* 引用 jquery 以及客戶端驗證腳本 *@ <script src="~/Scripts/jquery-1.8.2.min.js"></script> <script src="~/Scripts/jquery.validate.min.js"></script> <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script> @using (Html.BeginForm()) { <div> @Html.LabelFor(model => model.Name) @Html.EditorFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name) </div> <div> @Html.LabelFor(model => model.Age) @Html.EditorFor(model => model.Age) @Html.ValidationMessageFor(model => model.Age) </div> <div> @Html.LabelFor(model => model.Email) @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </div> <div> <input type="submit" value="提交" /> </div> } </body>
效果:
4、修改 Route 路由偽裝成 php
查找項目中的 RegisterRoutes 方法。默認路由如下:
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); }
主要關心 MapRoute 這個擴展方法的 url 參數和 defaults 參數。在 url 參數中,通過花括號映射參數名,例如 {controller} 則映射到 controller,{id} 則映射到 id。所以如果有 /A/B/C 的 url 傳入,則映射到 AController 的 B 方法並傳入 C 作為 id 參數的值。
當然我們也可以簡單修改路由來簡單偽造成 php 頁面。
修改 url 為 "{controller}-{action}-{id}.php"。
然后在項目根目錄的 Web.config 中添加一項,如下圖:
然后就可以訪問了,輸入例如 /Home-Index-0.php 之類的 url。效果:
當然也可以改成 jsp 或者其它來裝逼。
5、Route 路由中的 UrlParameter.Optional
接下來講解 defaults 參數,這個參數需要構造一個匿名類,並且這個匿名類的屬性的名稱需要跟 url 中相同。(當然多出一些沒用到的屬性也可)
默認路由中,controller 和 action 兩個都很好懂,就是沒有值的時候,分別使用 Home 和 Index。但 id 這個就不太好懂了。
經過查閱 msdn 及前人相關的資料我們可以知道,UrlParameter.Optional 是指假若沒有提供值,則給予默認值。還是舉個例子吧。
例如:
public class HomeController : Controller { public ActionResult Index(int id) { return View(); } }
那么這里的 id 就是 0。
public class HomeController : Controller { public ActionResult Index(string id) { return View(); } }
那么現在這個的 id 就是 null。
可見,UrlParameter.Optional 就相當於 default 關鍵字的作用。
6、繼承 ActionFilterAttribute 實現 AOP 面向切面編程
首先我們需要新建一個 Attribute 並繼承 ActionFilterAttribute。我就叫 TestActionAttribute 好了。
public class TestActionAttribute : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext filterContext) { Debug.WriteLine("OnActionExecuted"); base.OnActionExecuted(filterContext); } public override void OnActionExecuting(ActionExecutingContext filterContext) { Debug.WriteLine("OnActionExecuting"); base.OnActionExecuting(filterContext); } public override void OnResultExecuted(ResultExecutedContext filterContext) { Debug.WriteLine("OnResultExecuted"); base.OnResultExecuted(filterContext); } public override void OnResultExecuting(ResultExecutingContext filterContext) { Debug.WriteLine("OnResultExecuting"); base.OnResultExecuting(filterContext); } }
然后標注到 Action 上,運行。
我們可以見到按順序輸出:
OnActionExecuting
OnActionExecuted
OnResultExecuting
OnResultExecuted
在前面兩個方法間是執行我們的 Action,在后面兩個方法間是執行我們 Action 返回的 ActionResult。
那么這東西有什么用呢。舉個小例子,可以用做驗證。
修改 OnActionExecuting 方法。
public override void OnActionExecuting(ActionExecutingContext filterContext) { var request = filterContext.HttpContext.Request; var userAgent = request.UserAgent; if (userAgent.IndexOf("chrome",StringComparison.OrdinalIgnoreCase)>=0) { filterContext.Result = new ContentResult() { Content = "chrome 禁止訪問" }; } }
這里我們檢測 UserAgent,如果是 chrome 那么就不能訪問了。
運行之后,我們會發現 chrome 輸出禁止訪問,而 ie 等其它瀏覽器則仍然能繼續訪問。同時我們也可以通過斷點驗證到,chrome 訪問的情況下,標注的 Action 的方法體不會再執行,即設置了 filterContext 的 Result 屬性之后,就不再往下執行 Action 的流程了。(ActionResult 的流程還是依然執行的,也就是說 OnResultExecuting 和 OnResultExecuted 還是會繼續執行的說)
這個只是個小例子,具體實際業務情況可以做用戶登錄驗證、日志記錄等等。
好久沒碰 ASP.NET MVC,算是簡單復習下。