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

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

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

      MVC系列——MVC源碼學習:打造自己的MVC框架(三:自定義路由規則)

      前言:上篇介紹了下自己的MVC框架前兩個版本,經過兩天的整理,版本三基本已經完成,今天還是發出來供大家參考和學習。雖然微軟的Routing功能已經非常強大,完全沒有必要再“重復造輪子”了,但博主還是覺得自己動手寫一遍印象要深刻許多,希望想深入學習MVC的童鞋自己動手寫寫。好了,廢話就此打住。

       本文原創地址:http://www.rzrgm.cn/landeanfen/p/6016394.html

      MVC源碼學習系列文章目錄:

      一、版本三功能介紹

      在版本三里面,為了更加透徹理解UrlRoutingModule里面的路由功能,博主自己寫了一遍路由的讀取和配置過程,完成之后整個框架的代碼目錄結構如下:

      主要還是分為兩大塊:MVC目錄里面的對應著MvcHandler的邏輯,Routing目錄對象對應的UrlRoutingModule的邏輯。整個調用過程如下:

      看到這個圖,你可能仍然是懵比狀態。沒關系,如果你有興趣,且往下看。

      二、UrlRoutingModule的實現

      在整個UrlRoutingModule里面,我們所有的路由相關邏輯都和System.Web.Routing這個組件沒有任何聯系,完全是一塊獨立的區域。為了方便理解,這些文件的命名在原來System.Web.Routing組件里面的類前面都加上一個“Swift”。UrlRoutingModule的主要邏輯都在以下這些文件里面:

      1、SwiftRouteTable.cs代碼

      namespace Swift.MVC.Routing
      {
          public class SwiftRouteTable
          {
              //靜態構造函數,約束這個靜態對象是一個不被釋放的全局變量
              static SwiftRouteTable()
              {
                  routes = new SwiftRouteCollection();
              }
              private static SwiftRouteCollection routes;
              public static SwiftRouteCollection Routes
              {
                  get
                  {
                      return routes;
                  }
              }
          }
      }

      這個類主要作用就是定義一個靜態全局的SwiftRoutingCollection對象,在Global.asax里面可以配置這個路由集合。為什么是一個靜態全局變量呢?靜態是為了保證對象不被釋放(GC回收);全局是為了保證整個應用程序都可以訪問得到。

      2、SwiftRouteCollection.cs代碼

      上文在SwiftRouteTable里面定義一個靜態全局的SwiftRoutingCollection變量,我們來看這個里面到底有些什么東西。

      namespace Swift.MVC.Routing
      {
          public class SwiftRouteCollection
          {
              public SwiftRoute SwiftRoute { get; set; }
      
              public string Name { get; set; }
      
              //Global.asax里面配置路由規則和默認路由
              public void Add(string name, SwiftRoute route)
              {
                  SwiftRoute = route;
                  Name = name;
              }
      
              //通過上下文對象得到當前請求的路由表
              public SwiftRouteData GetRouteData(HttpContextBase context)
              {
                  var swiftRouteData = new SwiftRouteData();
                  //1.配置RouteHandler實例,這里的RouteHandler是在全局配置里面寫進來的
                  swiftRouteData.RouteHandler = SwiftRoute.RouteHandler;
      
                  //2.獲取當前請求的虛擬路徑和說明
                  var virtualPath = context.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + context.Request.PathInfo;
      
                  //3.先將默認路由配置寫入當前請求的路由表
                  //每次請求只能讀取默認值,而不能覆蓋默認值
                  swiftRouteData.RouteValue = new Dictionary<string, object>() ;
                  foreach (var key in this.SwiftRoute.DefaultPath)
                  {
                      swiftRouteData.RouteValue[key.Key] = key.Value;
                  }
      
                  //4.如果當前請求虛擬路徑為空,則訪問默認路由表。否則從當前請求的url里面去取當前的controller和action的名稱
                  if (!string.IsNullOrEmpty(virtualPath))
                  {
                      var arrTemplatePath = this.SwiftRoute.TemplateUrl.Split("{}/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                      var arrRealPath = virtualPath.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                      for (var i = 0; i < arrTemplatePath.Length; i++)
                      {
                          var realPath = arrRealPath.Length > i ? arrRealPath[i] : null;
                          if (realPath == null)
                          {
                              break;
                          }
                          swiftRouteData.RouteValue[arrTemplatePath[i]] = realPath;
                      }
                  }
                  //5.去讀當前請求的參數列表
                  var querystring = context.Request.QueryString.ToString();
                  if (string.IsNullOrEmpty(querystring))
                  {
                      return swiftRouteData;
                  }
                  var parameters = querystring.Split("&".ToArray(), StringSplitOptions.RemoveEmptyEntries) ;
                  var oparam = new Dictionary<string, string>();
                  foreach (var parameter in parameters)
                  {
                      var keyvalue = parameter.Split("=".ToArray());
                      oparam[keyvalue[0]] = keyvalue[1];
                  }
                  swiftRouteData.RouteValue["parameters"] = oparam;
                  return swiftRouteData;
              }
          }
      }

      這個類的結構也不復雜,兩個屬性,兩個方法。方法Add()用來給兩個屬性賦值,方法GetRouteData()主要作用注釋中已經注明。要詳細了解GetRouteData()方法的邏輯,我們有必要先看看SwiftRoute這個類型。

      3、SwiftRoute.cs代碼

      namespace Swift.MVC.Routing
      {
          public class SwiftRoute
          {
              public SwiftRoute()
              { }
      
              //在全局配置里面寫入路由規則以及默認配置
              public SwiftRoute(string url, Dictionary<string, object> defaultPath, IRouteHandler routeHandler)
              {
                  TemplateUrl = url;
                  DefaultPath = defaultPath;
                  RouteHandler = routeHandler;
              }
              public string TemplateUrl { get; set; }
      
              public IRouteHandler RouteHandler { get; set; }
      
              public Dictionary<string, object> DefaultPath { get; set; }
          }
      }

      在SwiftRoutingCollection的Add方法里面,我們需要傳入一個SwiftRoute對象,這里的SwiftRoute對象就包含了路由規則的url、默認路由地址、IRouteHandler接口對象三個重要信息,這三個信息都是在Global.asax里面寫入的,待會我們測試的再來詳細說明。

      4、SwiftRouteData.cs代碼

      在上文SwiftRouteCollection的GetRouteData()里面,返回了一個SwiftRouteData對象,這個對象的定義更加簡單,僅僅包含兩個屬性:

      namespace Swift.MVC.Routing
      {
          public class SwiftRouteData
          {
              public IRouteHandler RouteHandler { get; set; }
      
              public Dictionary<string, object> RouteValue { get; set; }
          }
      }

      RouteHandler屬性用來保存當前的IRouteHandler對象;

      RouteValue屬性用來保存當前請求的路由表。

      5、IRouteHandler.cs代碼

      上文多次提到了IRouteHandler接口,我們來看看那這個接口內容:

      namespace Swift.MVC.Routing
      {
          public interface IRouteHandler
          {
              System.Web.IHttpHandler GetHttpHandler(SwiftRouteData routeData, HttpContextBase context);
          }
      }

      這個接口的意義很簡單,只有一個方法,用來返回處理當前Http請求的HttpHandler對象。既然這里定義了這個接口,那我們順便也提一下這個接口的實現類,在當前項目的MVC目錄下面,有一個MvcRouteHandler類型:

      using Swift.MVC.Routing;
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Web;
      
      namespace Swift.MVC
      {
          public class MvcRouteHandler:IRouteHandler
          {
              /// <summary>
              /// 返回處理當前請求的HttpHandler對象
              /// </summary>
              /// <param name="routeData">當前的請求的路由對象</param>
              /// <param name="context">當前請求的下文對象</param>
              /// <returns>處理請求的HttpHandler對象</returns>
              public System.Web.IHttpHandler GetHttpHandler(SwiftRouteData routeData, HttpContextBase context)
              {
                  return new MvcHandler(routeData, context) ;
              }
          }
      }

      這個實現類作用更加明確,返回一個具體的HttpHandler對象。

      6、UrlRoutingModule.cs代碼

      有了上文的幾個類型做支撐,最后我們統籌調度的UrlRoutingModule閃亮登場了。

      namespace Swift.MVC.Routing
      {
          public class UrlRoutingModule : IHttpModule
          {
              #region Property
              private SwiftRouteCollection _swiftRouteCollection;
      
              [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly",
                  Justification = "This needs to be settable for unit tests.")]
              public SwiftRouteCollection SwiftRouteCollection
              {
                  get
                  {
                      if (_swiftRouteCollection == null)
                      {
                          _swiftRouteCollection = SwiftRouteTable.Routes;
                      }
                      return _swiftRouteCollection;
                  }
                  set
                  {
                      _swiftRouteCollection = value;
                  }
              }
              #endregion
      
              public void Dispose()
              {
                  //throw new NotImplementedException();
              }
      
              public void Init(HttpApplication app)
              {
                  app.PostResolveRequestCache += app_PostResolveRequestCache;
              }
      
              void app_PostResolveRequestCache(object sender, EventArgs e)
              {
                  var app = (HttpApplication)sender;
                  //0.將HttpContext轉換為HttpContextWrapper對象(HttpContextWrapper繼承HttpContextBase)
                  var contextbase = new HttpContextWrapper(app.Context);
                  PostResolveRequestCache(contextbase);
              }
      
              public virtual void PostResolveRequestCache(HttpContextBase context)
              {
                  //1.傳入當前上下文對象,得到與當前請求匹配的SwiftRouteData對象
                  SwiftRouteData routeData = this.SwiftRouteCollection.GetRouteData(context);
                  if (routeData == null)
                  {
                      return;
                  }
                  //2.從SwiftRouteData對象里面得到當前的RouteHandler對象。
                  IRouteHandler routeHandler = routeData.RouteHandler;
                  if (routeHandler == null)
                  {
                      return;
                  }
      
                  //3.根據RequestContext對象得到處理當前請求的HttpHandler(MvcHandler)。
                  IHttpHandler httpHandler = routeHandler.GetHttpHandler(routeData, context);
                  if (httpHandler == null)
                  {
                      return;
                  }
      
                  //4.請求轉到HttpHandler進行處理(進入到ProcessRequest方法)。這一步很重要,由這一步開始,請求才由UrlRoutingModule轉到了MvcHandler里面
                  context.RemapHandler(httpHandler);
              }
          }
      }

       和版本二里面的區別不大,很多屬性名和方法名都采用和版本二相同的規則,最大的區別就是在版本三里面,不再有RequestContext對象。UrlRoutingModule和MvcHandler兩者打交道的橋梁在版本二里面是RequestContext對象,在版本三里面變成了直接將當前的路由對象和上下文傳到MvcHandler里面。

      三、MvcHandler的實現

      在MvcHandler里面變化比較大的只有兩個:MvcHandler.cs和Controller.cs

      1、MvcHandler.cs

      namespace Swift.MVC
      {
          public class MvcHandler : IHttpHandler
          {
              public MvcHandler()
              { }
      
              public HttpContextBase SwiftContext { get; set; }
              public SwiftRouteData SwiftRouteData { get; set; }
              //通過構造函數將兩個對象傳過來,替代了原來RequestContext的作用
              public MvcHandler(SwiftRouteData routeData, HttpContextBase context)
              {
                  SwiftRouteData = routeData;
                  SwiftContext = context;
              }
      
              public virtual bool IsReusable
              {
                  get { return false; }
              }
      
              public virtual void ProcessRequest(HttpContext context)
              {
                  //寫入MVC的版本到HttpHeader里面
                  //AddVersionHeader(httpContext);
                  //移除參數
                  //RemoveOptionalRoutingParameters();
      
                  //1.從當前的RouteData里面得到請求的控制器名稱
                  string controllerName = SwiftRouteData.RouteValue["controller"].ToString();
      
                  //2.得到控制器工廠
                  IControllerFactory factory = new SwiftControllerFactory();
      
                  //3.通過默認控制器工廠得到當前請求的控制器對象
                  IController controller = factory.CreateController(SwiftRouteData, controllerName);
                  if (controller == null)
                  {
                      return;
                  }
      
                  try
                  {
                      //4.執行控制器的Action
                      controller.Execute(SwiftRouteData);
                  }
                  catch
                  {}
                  finally
                  {
                      //5.釋放當前的控制器對象
                      factory.ReleaseController(controller);
                  }
      
              }
          }
      }

      相比版本二,這個類多了一個有兩個參數的構造函數,用來將routeData和context傳進來。然后再ProcessRequest方法里面直接通過傳進來的對象去取當前請求的相關信息。

      2、Controller.cs

      namespace Swift.MVC
      {
          public abstract class Controller:ControllerBase,IDisposable
          {
              public override void Execute(SwiftRouteData routeData)
              {
                  //1.得到當前控制器的類型
                  Type type = this.GetType();
      
                  //2.從路由表中取到當前請求的action名稱
                  string actionName = routeData.RouteValue["action"].ToString();
      
                  //3.從路由表中取到當前請求的Url參數
                  object parameter = null;
                  if (routeData.RouteValue.ContainsKey("parameters"))
                  {
                      parameter = routeData.RouteValue["parameters"];
                  }
                  var paramTypes = new List<Type>();
                  List<object> parameters = new List<object>();
                  if (parameter != null)
                  {
                      var dicParam = (Dictionary<string, string>)parameter;
                      foreach (var pair in dicParam)
                      {
                          parameters.Add(pair.Value);
                          paramTypes.Add(pair.Value.GetType());
                      }
                  }
      
                  //4.通過action名稱和對應的參數反射對應方法。
                  //這里第二個參數可以不理會action字符串的大小寫,第四個參數決定了當前請求的action的重載參數類型
                  System.Reflection.MethodInfo mi = type.GetMethod(actionName,
                      BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase, null, paramTypes.ToArray(), null);
      
                  //5.執行該Action方法
                  mi.Invoke(this, parameters.ToArray());//調用方法
              }
      
              public void Dispose()
              {
                  //throw new NotImplementedException();
              }
          }
      }

      在Execute()方法里面,對基礎類型的Action方法參數重載提供了支持。

      四、測試以及代碼釋疑

      上文介紹了這么多,可能并不直觀,很多類之間如何聯系的看得并不清晰,反正如果是博主,別人這么介紹一個類又一個類,看完肯定還是蒙的的。那么我們來測試看下吧。

       首先,還是配置全局配置文件Global.asax

        public class Global : System.Web.HttpApplication
          {
      
              protected void Application_Start(object sender, EventArgs e)
              {
                  var defaultPath = new Dictionary<string, object>();
                  defaultPath.Add("controller", "Home");
                  defaultPath.Add("action", "Index");
                  defaultPath.Add("id", null);
                  defaultPath.Add("namespaces", "MyTestMVC.Controllers");
                  defaultPath.Add("assembly", "MyTestMVC");
      
                  SwiftRouteTable.Routes.Add("defaultRoute", new SwiftRoute("{controller}/{action}/{id}", defaultPath, new MvcRouteHandler()));
              }
          }

      看到這里應該知道上文中 SwiftRouteTable 、 SwiftRouteCollection 、 SwiftRoute 三個類的用處了吧,原來在這里。IRouteHandler的實例new MvcRouteHandler()也是在這里寫入的。

      然后啟動項目,我們默認訪問http://localhost:16792/Home/bootstrapTest這個地址,我們來看具體的過程:

      1、啟動項目,首先進到全局配置文件的Application_Start()方法

      這里告訴我們在SwiftRouteTable.Routes這個全局靜態變量里面,已經保存了路由規則、默認路由、RouteHandler對象三個重要的信息。這三個信息后面都會用到。

      2、然后請求進到UrlRoutingModule里面,取SwiftRouteCollection的值:

      我們看到,這里的SwiftRouteCollection的值就是在全局配置文件里面配置的類型。

      3、然后請求進到SwiftRouteCollection類的GetRouteData()方法里面。這個方法的作用很明顯,就是解析當前的請求的url,從中獲取當前的controller、action、參數等信息。這個方法執行完之后得到的SwiftRouteData對象,結果如下:

      這個對象包含兩個屬性,RouteHandler和當前請求的路由表。

      4、通過步驟3知道,當前的swiftRouteData對象包含了RouteHandler對象, IRouteHandler routeHandler = routeData.RouteHandler; 結果如下:

      5、得到RouteHandler對象之后,就是從該對象的GetHttpHandler()方法里面得到當前的HttpHandler。

      這個應該不難理解,將routeData和context傳入MvcHandler里面。這就是為什么之前MvcHandler里面有一個兩個參數的構造函數的原因。

      6、然后就是執行 context.RemapHandler(httpHandler); 將請求正式交給MvcHandler。

      7、在MvcHandler的ProcessRequest方法里面,首先從當前請求的路由表里面去控制器名稱,如下圖,得到”Home“:

      8、然后就是創建控制器工廠、從工廠里面得到當前請求的控制器的對象,這部分和之前變化不大。

      9、得到控制器對象之后,執行對應的當前請求的action方法,請求盡到Controller這個父類的Execute()方法里面

      10、通過反射,最終執行BootstrapTest()方法。

      11、BootstrapTest()方法執行完成之后,釋放當前的控制器對象: factory.ReleaseController(controller); 。請求結束。

      五、支持方法的重載

       博主對Swift.MVC框架進行了簡單的擴展,使得框架支持action方法的重載。比如我們在HomeController里面定義了如下方法

          public class HomeController : Controller
          {
              public void Index()
              {
                  HttpContext.Current.Response.Write("Hello MVC");
              }
      
              public void Index(string id)
              {
                  HttpContext.Current.Response.Write("Hello MVC  參數" + id);
              }
      
              public void Index(string aa, string bb)
              {
                  HttpContext.Current.Response.Write("Hello MVC  兩個參數");
              }
      
              public void BootstrapTest()
              {
                  .....
              }
      
              public void BootstrapTest(int id)
              {
                  .....
              }
          }

      1、請求默認路由地址:http://localhost:16792/

      2、請求地址:http://localhost:16792/Home/index?id=1

      3、請求地址:http://localhost:16792/Home/index?aa=kate&bb=lucy

      當然上文封裝都是只是通過url傳遞參數的情況,等有時間可以擴展下,使得支持通過post請求傳遞參數。

      六、總結

      通過上一篇和這一篇,我們基本上把MVC的核心原理涉及到的技術都重寫了一遍,等有時間再擴展一個自己的”View“,加上模型驗證,數據綁定,我們的Swift.MVC就算是一個相對完整的微型MVC框架了。當然,此框架僅僅是從學習理解MVC的原理層面去實現的,如果要應用于項目,還要考慮很多東西,不論如何,是個好的開始,有時間繼續完善。源碼地址

      如果你覺得本文能夠幫助你,可以右邊隨意 打賞 博主,也可以 推薦 進行精神鼓勵。你的支持是博主繼續堅持的不懈動力。

      本文原創出處:http://www.rzrgm.cn/landeanfen/

      歡迎各位轉載,但是未經作者本人同意,轉載文章之后必須在文章頁面明顯位置給出作者和原文連接,否則保留追究法律責任的權利

       

      posted @ 2016-11-01 14:01  懶得安分  閱讀(10918)  評論(12)    收藏  舉報
      主站蜘蛛池模板: 阳泉市| 91亚洲国产三上悠亚在线播放| 中文字幕制服国产精品| 精品午夜福利在线观看| 99久久精品国产一区二区| 九九热精彩视频在线免费| 欧美丰满熟妇xxxx性ppx人交| 中文日产乱幕九区无线码| 国产午夜福利视频一区二区| 亚洲国产精品日韩在线| 国产不卡一区二区三区视频| 2019亚洲午夜无码天堂| 亚洲欧美日韩愉拍自拍美利坚| av在线播放无码线| 中文字幕久久久久人妻| 无人去码一码二码三码区| 国产成人综合在线女婷五月99播放| 日本激情久久精品人妻热| 极品尤物被啪到呻吟喷水| 国产精品久久中文字幕| 乱60一70归性欧老妇| 日本久久精品一区二区三区| 麻豆一区二区三区香蕉视频| 国产精品毛片久久久久久久 | 亚洲中文久久久精品无码| 熟妇的味道hd中文字幕| 珲春市| 国产三级精品三级在线区| 国产一卡2卡三卡4卡免费网站| 久9视频这里只有精品| 国产内射xxxxx在线| 亚洲成年av天堂动漫网站| 国产伦精品一区二区亚洲| 大香伊蕉在人线国产最新2005| 又粗又硬又黄a级毛片| 黄色三级亚洲男人的天堂| 99久久国产综合精品女图图等你| 国产成人精品无人区一区| 国产无套内射又大又猛又粗又爽| 精品偷自拍另类精品在线| 狠狠亚洲色一日本高清色|