1. 程式人生 > >《精通ASP.NET MVC4》學習筆記

《精通ASP.NET MVC4》學習筆記

實例 重寫方法 fig 功能 add 相同 stat 筆記 .net

第7-11章 SportStore項目實踐

(見個人項目CY.SportsStoreMVC)

第12章 MVC項目綜述

理解約定優於配置:不用明確的配置應用程序中的某種關聯,只要遵守某種約定,一切都會正常工作。(可以修改這種約定,不過會帶來大量的修改工作。個人理解:將關聯寫入配置文件,應用程序需要使用大量的反射機制獲取配置中的關聯,這反而會降低應用程序的性能)

約定包括命名約定、控制器和視圖關聯約定、布局約定等。

第13章 URL路由(處理輸入URL)

路由系統的兩個功能

1、匹配請求(輸入)URL,找到對應的控制器和動作方法;

2、生成響應(輸出)URL,方便下一次請求。

名詞理解

URL中片段值-->域名之後用‘/’分隔的內容;

片段變量-->路由中URL模式中以占位符的形式定義的部分;

靜態片段—>URL模式中非占位符形式的部分(URL中片段內容必須與其相同才能匹配)

:路由系統和MVC框架是沒有任何關聯的(路由是asp.net平臺下的一種技術),只是單純的匹配請求URL中的片段(將路由中定義的模式與請求URL匹配,若匹配成功,將URL中片段的值賦給模式中定義的片段變量),匹配出來的片段變量值會沿著請求管道傳給MVC應用程序(路由系統並不關心MVC系統中是否存在相應的Controller和action)

路由匹配規則:按片段順序進行匹配,配少不配多,少的部分由默認值代替(解釋:URL中的片段數不能多於路由模式中定義的片段變量數,一個片段值匹配一個片段變量,若URL中未提供路由模式中定義的某一片段變量的值,使用路由中定義的默認值代替)

路由匹配順序:一般按照其定義順序逐個匹配,原則是具體的放在前面,保證先被匹配到。

使用路由中的默認值替換URL中指定的controller或action

route.MapRoute("shopSchema", "shop/{action}", new {controller="home"});

該路由會將url中shop/index請求轉換到home/index下

通過請求URL給MVC動作方法傳值的幾種方式:

1、獲取URL中查詢變量的值(?後面的值) ?id=111 –> Request["id"]

2、將URL中的某一片斷值(片段用‘/’分隔)傳給路由模式中定義的片段變量(定義的該片段變量必須是自定義的,非controller、action等默認的),然後再用動作方法參數匹配該片段變量獲取該值(匹配過程由模型綁定器完成,方法參數名和片段變量名要一致(不區分大小寫)才能匹配成功)(在動作方法中使用RouteData.Values屬性同樣可以獲取到路由中片段變量的值)

使用{*catchall}片段變量定義可變長路由:

//該路由模式可匹配任意片段數的URL,URL中前三個片段之後的所有片段都將賦給catchall

routes.MapRoute(“MyRoute”,”{controller}/{action}/{id}/{*catchall}”,new {controller=”Home”,action=”Index”,id=”UrlParameter.Optional”});

路由中指定優先查找的控制器類:

在一個字符串數組中指定要優先處理的控制器類所在命名空間,指示mvc框架優先查找指定的命名空間,若指定的命名空間中沒有找到相應的控制器類,則回到mvc框架的正常默認行為。

註:

1、字符串數組中指定的多個命名空間不具有優先順序,若想指定多個優先查找的命名空間,則必須定義多條不同的路由;

2、使用myRoute.DataTokens[“UseNamespaceFallback”]=false通知mvc框架只查找字符串數組中指定的命名空間。

Route myRoute = routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional },
                namespaces: new[] { "CY.SportsStoreMVC.WebUI.Controllers" }
            );
            myRoute.DataTokens["UseNamespaceFallback"] = false;

URL請求磁盤文件:

默認情況下,路由系統在評估應用程序路由之前,會先檢查是否有磁盤文件和url匹配,若存在匹配的磁盤文件,則直接請求該磁盤文件。

若想要路由系統評估磁盤文件,又想要能夠直接請求某一類型磁盤文件,可以使用如下方式:

//通知路由系統評估磁盤文件
routes.RouteExsitingFiles = true;
//通知路由系統若匹配到這一URL模式,則不再評估後續路由,直接請求該URL
routes.IgnoreRoute("Content/{filename}.html");

第14章 高級路由特性(使用路由系統生成輸出URL)

使用路由系統生成輸出URL的好處是:當路由方案發生變化時,這種變化會自動的反映到輸出URL,相對於通過硬編碼的方式寫入URL,應用程序具有更好的可維護性。

路由系統生成輸出URL的原理:

路由系統會根據當前查找到的片段變量的值來按順序匹配路由表中定義的路由,匹配成功的三個條件如下:

一、為當前評估的路由找到各片段變量的值,這些值的來源及其查找順序如下:

1、ActionLink或Action方法中routeValues參數明確提供的值,routeValues參數可以是匿名類型,也可以是RouteValueDictionary

2、當前請求上下文的RouteData(意指當前請求URL中為其匹配的路由URL模式中設置的片段值)

3、當前要評估的路由中defaults默認值

二、對於未出現在待評估路由的url模式中但設置了默認值的片段變量,mvc應用程序最好不要提供該值,否則提供的值必須與路由中定義的默認值匹配才可以;

三、為當前評估的路由找到各片段變量的值必須滿足路由中定義的約束條件。

註:URL模式中片段變量是按順序被賦值的,當某一片段變量被routeValues參數中提供的值賦值成功後,其後續片段變量便不能被其它數據源賦值(如當前請求的RouteData),所以最好在routeValues參數中明確的給URL模式中的每一個片段變量提供值

(第14章 以上知識點總結於書本和網上,未經實例驗證)

定制路由

1、自定義路由類必須繼承自RouteBase基類

public class LegacyRoute:RouteBase

2、必須重寫方法GetRouteData和VirtualPathData

//路由系統將調用GetRouteData方法用於匹配入站URL
 public override RouteData GetRouteData(HttpContextBase httpContext)
//路由系統調用此方法使用獲取到的路由數據(參數RouteValueDictionary values)生成出站URL
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)

3、註冊添加自定義路由

public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            //自定義路由:
            routes.Add(new LegacyRoute("~/articles/windows_3.1_overview.html", "~/old/.net_1.1_Class"));

自定義路由處理程序

路由處理程序是連接路由系統和MVC框架的橋梁,自定義路由處理程序必須實現IRouteHandler接口,負責完成控制器查找、動作方法調用、視圖渲染等功能。(較復雜,暫不深究)

定義與使用MVC應用程序中的區域(Areas)

1、添加區域:右鍵solution explorert添加區域,區域目錄結構Areas/{AreaName},{AreaName}文件夾下面controller、Models、Views等

2、添加區域之後,{AreaName}文件夾下有一個AdminAreaRegistration.cs文件,AdminAreaRegistration類派生於AreaRegistration,用於註冊當前區域專屬路由:

public class AdminAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get
            {
                return "Admin";
            }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            //如果給路由賦名,必須確保該名稱在整個應用程序內而非該區域內是唯一的
            //MapRoute方法會自動將在此處註冊的路由查找範圍限制到包含該區域控制所在命名空間中,
            //這意味著在該區域中添加的控制器,必須在其默認的命名空間中定義
            context.MapRoute(
                "Admin_default",
                "Admin/{controller}/{action}/{id}",
                new { action = "Index", id = UrlParameter.Optional }
            );
        }
    }

3、在MVC應用程序Global.asax文件中會自動添加一行代碼註冊區域路由:

protected void Application_Start()
        {
            //註冊區域路由:
            //系統將使用此方法遍歷所有派生於AreaRegistration的類,並調用這些類的RegisterArea方法
            //註:由於路由是按順序評估的,RegisterAllAreas方法的調用必須在RegisterRoutes方法的調用之前,否則可能進行不正確的匹配
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

4、不同區域之間的鏈接跳轉:

在使用匿名類型定義的RouteValueCollection中,通過給片段變量area賦值,通知應用程序切換不同的區域,賦空字符串值時將切換到項目主區。

@Html.ActionLink("click me", "GetLegacyURL", "Legacy", new { area = "", legacyURL = "~/articles/windows_3.1_overview.html" }, null)

第15章 控制器與動作

控制器

標準控制器派生於Controller類,Controller實現了IController接口(同時還實現了很多其它的接口),實現了IController中的唯一Execute方法,在Execute方法中負責調用自定義的動作方法。

Controller類為其派生類提供了一組便利屬性(convenience property),使用點語法通過ControllerContext實例獲取。

便利屬性中提供的常用上下文對象(獲取請求相關信息)

string strGetParam = this.ControllerContext.HttpContext.Request.QueryString["getParam"];
            string strPostParam = this.ControllerContext.HttpContext.Request.Form["postParam"];
            HttpCookie cookies = this.ControllerContext.HttpContext.Request.Cookies["cookie"];
            RouteBase route = this.ControllerContext.RouteData.Route;
            RouteData routeData = route.GetRouteData(this.ControllerContext.HttpContext);
            RouteData routeData2 = this.ControllerContext.RouteData;
            string strController = routeData2.Values["controller"].ToString();
            string strAction = routeData2.Values["action"].ToString();
            //未完待續...

控制器接受輸入數據(如查詢字符串、表單值,以及路由數據)的三種方法:

1、使用上述便利屬性中的上下文對象進行提取;

2、使用動作方法參數獲取數據;

使用動作方法需要註意的幾點:

1、MVC框架使用內建的值提供器(value provider)和模型綁定器(model binder)組件獲取參數實例填充參數,值提供器負責從相關上下文對象(如request.QueryString、Request.Form、Request.Files)抓取數據,模型綁定器負責將這些數據映射成參數數據類型並填充參數;

2、動作方法參數未匹配到對應數據的情況下:

對於引用類型,會默認提供null值;

對於值類型,將會拋出異常。解決辦法:使用可空類型定義參數(如int? i//在未提供i值的情況下,會使用null值代替);使用可選參數定義參數默認值(如int i=1),可選參數可用於字面類型(字面類型指不需要使用new關鍵字創建類型,包括string)

3、如果提供的參數值無法轉換成參數類型,系統將使用該類型的默認值,並添加一個模型驗證錯誤。

3、使用模型綁定(後續章節闡述)

動作

動作方法處理接受的輸入請求後產生輸出的原理:

動作方法處理完輸入請求後返回一個ActionResult類型的對象給MVC框架,MVC框架會調用ActionResult對象中的ExecuteResult方法處理輸出響應。ActionResult實際上是一種命令模式(命令模式是一種設計模式,指為執行某一操作的命令(如調用某一方法)封裝一個對象,該對象包含一些信息,如目標方法,目標方法屬主(方法所屬對象)以及調用方法所需參數)。

將數據從動作方法傳遞給視圖的幾種方式:

1、使用視圖模型對象;

若一個視圖沒有指定模型類型,那麽視圖為弱類型視圖,視圖將把傳遞過來的模型對象視為object處理,使用前需要先轉換成相應類型。指定視圖模型類型:@model DateTime,此時為強類型視 圖。

2、使用ViewBag動態對象;

註:ViewBag無法跨請求使用。

3、使用TempData對象(非動態對象,使用鍵/值對表示);

註:TempData可以跨請求使用,在其數據被讀取後會被標記為刪除,在請求處理完成之後會被馬上刪除。

使用TempData對象的peek方法讀取數據,而不標記刪除;使用keep方法保留一個將被刪除的數據(只保留一次)。

《精通ASP.NET MVC4》學習筆記