<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      從零開始學習 ASP.NET MVC 1.0 (三) Controller/Action 深入解析與應用實例

      《從零開始學習ASP.NET MVC 1.0》 文章導航

       

      一.摘要

      一個Url請求經過了Routing處理后會調用Controller的Action方法. 中間的過程是怎樣的? Action方法中返回ActionResult對象后,如何到達View的? 本文將講解Controller的基本用法,  深入分析Controller的運行機制, 并且提供了創(chuàng)建所有類型Action的代碼. 值得學習ASP.NET MVC時參考.

      二.承上啟下

      在上一篇文章中, 我已經學會了如何使用Routing獲取Controller和Action, 隨后的程序會調用Controller中的Action方法.

      每個Action方法都要返回一個ActionResult對象. 一個Action會將數(shù)據(jù)傳遞給View,如圖:

      image

      三.Controller與Action的作用

      1.職責

      Controller負責將獲取Model數(shù)據(jù)并將Model傳遞給View對象.通知View對象顯示.

      2.ASP.NET MVC中的Controller和Action

      在ASP.NET MVC中, 一個Controller可以包含多個Action. 每一個Action都是一個方法, 返回一個ActionResult實例.

      ActionResult類包括ExecuteResult方法, 當ActionResult對象返回后會執(zhí)行此方法.

      下面分層次的總結Controller 處理流程:

      1. 頁面處理流程

      發(fā)送請求 –> UrlRoutingModule捕獲請求 –> MvcRouteHandler.GetHttpHandler() –> MvcHandler.ProcessRequest()

      2.MvcHandler.ProcessRequest() 處理流程:

      使用工廠方法獲取具體的Controller –> Controller.Execute() –> 釋放Controller對象

      3.Controller.Execute() 處理流程

      獲取Action –> 調用Action方法獲取返回的ActionResult –> 調用ActionResult.ExecuteResult() 方法

      4.ActionResult.ExecuteResult() 處理流程

      獲取IView對象-> 根據(jù)IView對象中的頁面路徑獲取Page類-> 調用IView.RenderView() 方法(內部調用Page.RenderView方法)

      通過對MVC源代碼的分析,我們了解到Controller對象的職責是傳遞數(shù)據(jù),獲取View對象(實現(xiàn)了IView接口的類),通知View對象顯示.

      View對象的作用是顯示.雖然顯示的方法RenderView()是由Controller調用的,但是Controller僅僅是一個"指揮官"的作用, 具體的顯示邏輯仍然在View對象中.

      需要注意IView接口與具體的ViewPage之間的聯(lián)系.在Controller和View之間還存在著IView對象.對于ASP.NET程序提供了WebFormView對象實現(xiàn)了IView接口.WebFormView負責根據(jù)虛擬目錄獲取具體的Page類,然后調用Page.RenderView().

      四.ActionResult解析

      通過上面的流程,我們知道了ActionResult對象在整個流程中的作用.ActionResult是一個抽象類, 在Action中返回的都是其派生類.下面是我整理的ASP.NET MVC 1.0 版本中提供的ActionResult派生類:

      類名 抽象類 父類 功能
      ContentResult     根據(jù)內容的類型和編碼,數(shù)據(jù)內容.
      EmptyResult     空方法.
      FileResult abstract   寫入文件內容,具體的寫入方式在派生類中.
      FileContentResult   FileResult 通過 文件byte[] 寫入文件.
      FilePathResult   FileResult 通過 文件路徑 寫入文件.
      FileStreamResult   FileResult 通過 文件Stream 寫入文件.
      HttpUnauthorizedResult     拋出401錯誤
      JavaScriptResult     返回javascript文件
      JsonResult     返回Json格式的數(shù)據(jù)
      RedirectResult     使用Response.Redirect重定向頁面
      RedirectToRouteResult     根據(jù)Route規(guī)則重定向頁面
      ViewResultBase abstract   調用IView.Render()
      PartialViewResult   ViewResultBase 調用父類ViewResultBase 的ExecuteResult方法.
      重寫了父類的FindView方法.
      尋找用戶控件.ascx文件
      ViewResult   ViewResultBase 調用父類ViewResultBase 的ExecuteResult方法.
      重寫了父類的FindView方法.
      尋找頁面.aspx文件

      目前ASP.NET MVC還沒有提供官方的ActionResult列表.上面的列表是我在源代碼中分析得出的.有些解釋的可能不夠清楚,請諒解.

      下面我將列舉各個ActionResult的實例.

      五.實例應用

      1.添加Controller

      安裝了ASP.NET MVC后, 在項目上點擊右鍵會找到添加Controller項:

      image

      2.添加Action

      下面這個類提供了返回各種類型的ActionResult的Action實例:

      public class DemoController : Controller
          {
      
              /// <summary>
              /// http://localhost:1847/Demo/ContentResultDemo
              /// </summary>
              /// <returns></returns>
              public ActionResult ContentResultDemo()
              {
                  string contentString = "ContextResultDemo!";
                  return Content(contentString);
              }
      
              /// <summary>
              /// http://localhost:1847/Demo/EmptyResultDemo
              /// </summary>
              /// <returns></returns>
              public ActionResult EmptyResultDemo()
              {
                  return  new EmptyResult();
              }
      
              /// <summary>
              /// http://localhost:1847/Demo/FileContentResultDemo
              /// </summary>
              /// <returns></returns>
              public ActionResult FileContentResultDemo()
              {
                  FileStream fs = new FileStream(Server.MapPath(@"/resource/Images/1.gif"), FileMode.Open, FileAccess.Read);
                  byte[] buffer = new byte[Convert.ToInt32(fs.Length)];
                  fs.Read(buffer, 0, Convert.ToInt32(fs.Length) );
                  return File(buffer, @"image/gif");
              }
      
              /// <summary>
              /// http://localhost:1847/Demo/FilePathResultDemo
              /// </summary>
              /// <returns></returns>
              public ActionResult FilePathResultDemo()
              {
                  //可以將一個jpg格式的圖像輸出為gif格式
                  return File(Server.MapPath(@"/resource/Images/2.jpg"), @"image/gif");
              }
      
              /// <summary>
              /// http://localhost:1847/Demo/FileStreamResultDemo
              /// </summary>
              /// <returns></returns>
              public ActionResult FileStreamResultDemo()
              {            
                  FileStream fs = new FileStream(Server.MapPath(@"/resource/Images/1.gif"), FileMode.Open, FileAccess.Read);
                  return File(fs, @"image/gif");
              }
      
              /// <summary>
              /// http://localhost:1847/Demo/HttpUnauthorizedResultDemo
              /// </summary>
              /// <returns></returns>
              public ActionResult HttpUnauthorizedResultDemo()
              {
                  return new HttpUnauthorizedResult();
              }
      
              /// <summary>
              /// http://localhost:1847/Demo/JavaScriptResultDemo
              /// </summary>
              /// <returns></returns>
              public ActionResult JavaScriptResultDemo()
              {
                  return JavaScript(@"alert(""Test JavaScriptResultDemo!"")");
              }
      
              /// <summary>
              /// http://localhost:1847/Demo/JsonResultDemo
              /// </summary>
              /// <returns></returns>
              public ActionResult JsonResultDemo()
              {
                  var tempObj = new { Controller = "DemoController", Action = "JsonResultDemo" };
                  return Json(tempObj);
              }
      
              /// <summary>
              /// http://localhost:1847/Demo/RedirectResultDemo
              /// </summary>
              /// <returns></returns>
              public ActionResult RedirectResultDemo()
              {
                  return Redirect(@"http://localhost:1847/Demo/ContentResultDemo");
              }
      
              /// <summary>
              /// http://localhost:1847/Demo/RedirectToRouteResultDemo
              /// </summary>
              /// <returns></returns>
              public ActionResult RedirectToRouteResultDemo()
              {
                  return RedirectToAction(@"FileStreamResultDemo");
              }
      
              /// <summary>
              /// http://localhost:1847/Demo/PartialViewResultDemo
              /// </summary>
              /// <returns></returns>
              public ActionResult PartialViewResultDemo()
              {
                  return PartialView();
              }
      
              /// <summary>
              /// http://localhost:1847/Demo/RedirectToRouteResultDemo
              /// </summary>
              /// <returns></returns>
              public ActionResult ViewResultDemo()
              {
                  //如果沒有傳入View名稱, 默認尋找與Action名稱相同的View頁面.
                  return View();
              }
      
          }

      在文章最后提供有完整實例代碼下載.

      六.Controller 深入分析

      在研究Controller/Action的流程過程中, 發(fā)現(xiàn)了ASP.NET MVC一些問題.

      1.Routing組件與MVC框架的結合

      Routing組件和ASP.NET MVC并不是一個項目, 在ASP.NET MVC中僅僅是使用了Routing組件, 在源代碼中是通過dll的方式引用的.Routing組件已經包含在.net framework 3.5 sp1中了.

      那么ASP.NET MVC是如何應用Routing組件的呢?

      Routing組件獲取了Url中的數(shù)據(jù)后, 會將數(shù)據(jù)保存在一個 RouteData 對象中.并將請求傳遞給一個實現(xiàn)了IRouteHandler接口的對象. 在Asp.net MVC中提供的MvcRouteHandler類實現(xiàn)了此接口, Routing 將請求傳遞給MvcRouteHandler的GetHttpHandler方法.下面是源代碼:

      IRouteHandler接口:

          public interface IRouteHandler
          {
              IHttpHandler GetHttpHandler(RequestContext requestContext);
          }

       

      MvcRouteHandler類:

          public class MvcRouteHandler : IRouteHandler {
              protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
                  return new MvcHandler(requestContext);
              }
      
              #region IRouteHandler Members
              IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) {
                  return GetHttpHandler(requestContext);
              }
              #endregion
          }

       

      曾經我認為IRouteHandler是多余的, 用IHttpHandler就夠了. 現(xiàn)在知道了為何要定義這個接口. 主要是為了傳遞RouteData對象.GetHttpHandler方法需要一個RequestContext 對象.RequestContext 是 System.Web.Routing程序集中的類, 里面除了處理請求需要的HttpContextBase對象,還包括了一個RouteData對象.

      RequestContext類:

          public class RequestContext
          {
              public RequestContext(HttpContextBase httpContext, RouteData routeData);
              public HttpContextBase HttpContext { get; }
              public RouteData RouteData { get; }
          }

      Routing組件在Web.Config中注冊了一個HttpModule: System.Web.Routing.UrlRoutingModule, 而不是HttpHandler:

      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

       

      可惜看不到這個類的源代碼. 所有請求最后都是要傳遞給IHttpHandler對象處理, 主要的工作是編譯頁面, 所以我猜測這個Module將請求截獲后通過IRouteHandler接口對象獲取一個HttpHandler, 然后將處理移交給獲取到的HttpHandler.

       

      ASP.NET MVC 中實現(xiàn)了IHttpHandler接口的類是MvcHandler, MvcRouteHandler.GetHttpHandler方法就是返回一個MvcHandler對象. MvcHandler類的構造函數(shù)需要傳入一個RequestContext對象. 實現(xiàn)的IHttpHandler接口方法處理過程中都需要依賴這個對象.

      但是微軟在這里的處理有一些不足. MvcHandler雖然實現(xiàn)了IHttpHandler接口但是不能被當作IHttpHandler接口使用. 因為IHttpHandler中沒有定義RequestContext屬性, 如果一個MvcHandler對象此屬性沒有賦值則會出錯, 也沒有將默認的無參數(shù)構造函數(shù)設置為private, 所以理論上可以很隨意的實例化一個MvcHandler而不為其RequestContext屬性賦值.

      IRouteHandler想實現(xiàn)的語意是: 返回一個具有RequestContext屬性的IHttpHandler對象.

      但是最后的實現(xiàn)結果是: 提供"返回IHttpHandler對象"的方法,  此方法接收RequestContext對象參數(shù).

      還需要注意ControllerContext類. 在Controller的處理過程中使用此對象作為保存上下文數(shù)據(jù)的容器.下面是這幾個類的包含關系:

      image

      可以看到在ControllerContext中包含了RequestContext對象,但是又將RequestContext對象中的兩個屬性提取到自己的類中.如果僅僅是為了使用方便而這么做, 個人認為不是一個好的設計.數(shù)據(jù)對象的存儲職責也應該明確,使用ControllerContext.RequestContext.RouteData 的方式更容易被人理解.

      PS:這種方式類似于方法內聯(lián).對于屬性JIT為了效率會幫助我們做內聯(lián).而僅僅是為了使用方便.

      2.IView 與 View對象的關系

      所以從系統(tǒng)的角度上看, 實現(xiàn)了IView接口的對象才是View.

      但是從實現(xiàn)效果上看, 具體的aspx或者ascx頁面才是View.

      當?shù)谝淮慰吹絀View接口時我認為它應該是"View角色"需要實現(xiàn)的接口. 但是結果并不是這樣.

      在我們的系統(tǒng)中View對象應該是aspx或者ascx文件. 而且并不是所有的ActionResult都需要找到aspx或者ascx文件, 事實上只有PartialViewResult 和 ViewResult 才會去尋找View對象.其他的ActionResult要么是返回文件, 要么是跳轉等等.

      那么兩者的關系到底是怎樣的? 其實其中的過程需要牽扯到這幾個接口和類:

      IViewEngine, ViewEngineResult, ViewEngineCollection

      ViewEngine是View引擎, ViewEngineCollection是一個引擎集合,里面保存了各種尋找View的引擎.但是在目前的源代碼中只有WebFormViewEngine : VirtualPathProviderViewEngine : IViewEngine

      這一系列WebForm使用的引擎.引擎的作用有兩個:

      1.尋找Page/用戶控件的路徑

      2.根據(jù)路徑創(chuàng)建IView對象.也就是根據(jù)頁面的物理文件創(chuàng)建IView接口對象.

      而且目前實現(xiàn)了IView接口的對象也只有一個:

      WebFormView

      WebFormViewEngine 根據(jù)頁面路徑, 將一個頁面地址轉化為一個WebFormView對象,也就是一個IView接口對象.

      至此IView接口和Page頁面類仍然沒有任何關系, IView對象只是保存了頁面的物理路徑.

      接著在IView的Render事件中,根據(jù)物理路徑創(chuàng)建了一個頁面的object實例,注意看這一段代碼:

                  object viewInstance = BuildManager.CreateInstanceFromVirtualPath(ViewPath, typeof(object));
                  if (viewInstance == null) {
                      throw new InvalidOperationException(
                          String.Format(
                              CultureInfo.CurrentUICulture,
                              MvcResources.WebFormViewEngine_ViewCouldNotBeCreated,
                              ViewPath));
                  }
      
                  ViewPage viewPage = viewInstance as ViewPage;
                  if (viewPage != null) {
                      RenderViewPage(viewContext, viewPage);
                      return;
                  }
      
                  ViewUserControl viewUserControl = viewInstance as ViewUserControl;
                  if (viewUserControl != null) {
                      RenderViewUserControl(viewContext, viewUserControl);
                      return;
                  }

      viewInstance 就是通過物理路徑創(chuàng)建的頁面對象.但是他的類型是object, 而且程序嘗試將其分別轉化為ViewPage對象和ViewUserControl對象.

      我想很多人都看到了這里的設計不足.現(xiàn)在我們只能"約定": 所有的MVC中的頁面對象都必須繼承自ViewPage或者ViewUserControl類, 否則程序就會出錯.產生這種不足的原因就是IView接口和ViewPage沒有任何的耦合性, 完全是硬編碼進去的.

      為什么不讓頁面直接實現(xiàn)IView接口? 然后嘗試將頁面轉化為IView接口對象, 而不是ViewPage, 這樣才是好的設計. 其實微軟知道什么是好的設計, 我猜測他們遇到的困難是Page對象和IView接口的沖突. 因為兩者都需要Render. 如果在IView中定義自己的Render名稱, 那就意味著ASP.NET MVC開發(fā)小組要自己處理頁面的顯示邏輯, 而現(xiàn)在ASP.NET WebForm模式下面的頁面顯示引擎又不能復用, 重新開發(fā)自己的一套顯示引擎成本又太大, 才出此下策.

      以上只是猜測.這種設計的缺陷雖然可以接受, 但是真的是讓我好幾天陷入了看不懂代碼的痛苦之中.還好, 現(xiàn)在可以解脫了.

       

      七.如何在MVC項目中使用MVC源代碼項目

      另外在為了跟蹤實現(xiàn)過程, 我將ASP.NET MVC的源代碼項目添加到了實例項目中, 其中有一些需要注意的地方:

      1. 將實例項目中的System.Web.Mvc引用刪除, 改成項目引用.

      2. 需要在Web.Config中注釋掉程序集引用:

              <compilation debug="true">
                  <assemblies>
                      <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
                      <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
                      <add assembly="System.Web.Abstractions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
                      <add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
                      <!-- <add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>-->
                      <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
                      <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
                      <add assembly="System.Data.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
                  </assemblies>
              </compilation>

      注釋掉的程序集存在于GAC中, 但是我們現(xiàn)在不希望使用GAC中的程序集, 而是引用項目.

      3. 將View目錄下的Web.Config中的所有System.Web.Mvc相關的 PublicKeyToken 都修改為 null:

          <pages
              validateRequest="false"
              pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
              pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
              userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
            <controls>
              <add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" namespace="System.Web.Mvc" tagPrefix="mvc" />
            </controls>
          </pages>

      八.總結

      首先很抱歉在本系列文章開篇時承諾的每日一篇僅僅堅持了2天.具體原因就不解釋了.這篇文章的出爐歷時半個月, 并且經歷了ASP.NET MVC從RC,RC2直到最近的1.0版本的演變. 在查看MVC源代碼上花費了大量的時間, 希望付出的努力能夠為大家研究學習ASP.NET MVC帶來幫助.

      實例源代碼下載地址:

      https://files.cnblogs.com/zhangziqiu/Asp.net-MVC-3-Demo.rar

      posted @ 2009-03-11 19:50  ziqiu.zhang  閱讀(50285)  評論(51)    收藏  舉報
      主站蜘蛛池模板: 中文字幕第一页亚洲精品| 永胜县| 福利成人午夜国产一区| 国产乱对白刺激视频| 亚洲人成亚洲人成在线观看| 国产精品福利自产拍久久| 亚洲AV日韩AV激情亚洲| 日韩国产精品中文字幕| 免费观看全黄做爰大片国产| 欧美成人精品手机在线| 麻豆a级片| 性色av一区二区三区精品| 亚洲色偷偷色噜噜狠狠99| 韩国无码av片在线观看| 中文字幕av国产精品| 极品美女扒开粉嫩小泬图片| 日本丰满人妻xxxxxhd| av中文字幕一区二区| 寿宁县| 国产午夜福利精品视频| 秋霞鲁丝片av无码少妇| 久久夜色精品久久噜噜亚| 亚洲日韩久热中文字幕| 无码人妻人妻经典| 精品蜜臀国产av一区二区| 动漫AV纯肉无码AV电影网| 成人欧美日韩一区二区三区| 新源县| 欧美巨大极度另类| 久久这里都是精品二| 国产精品久久久久9999| 亚洲乱色一区二区三区丝袜| 亚洲熟女乱综合一区二区| 亚洲综合一区二区精品导航| 婷婷四房播播| 亚洲最大日韩精品一区| 国产成人精品成人a在线观看| 日韩人妻无码精品久久| 国产欧美日韩精品第二区| 亚洲国产长腿丝袜av天堂| 国产色悠悠在线免费观看|