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

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

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

      Mvc 模塊化開發

            在Mvc中,標準的模塊化開發方式是使用Areas,每一個Area都可以注冊自己的路由,使用自己的控件器與視圖。但是在具體使用上它有如下兩個限制

            1.必須把視圖文件放到主項目的Areas文件夾下才能生效,否則運行時會發生找不到視圖的錯誤。

            2.在實際開發中,這種開發方式只能建立一個項目,所有的開發工作都在這個項目里完成,非常不利于團隊大規模開發。

       

            顯然,上面的兩點限制嚴重制約了插件化開發實際運用。為了實現真正的插件化開發,大家積極的思考研究,又找到了如下幾種方式

            1.MVC Portable Areas

            這種開發方式,是使用單獨的項目進行Areas開發,然后將所有頁面,樣式,腳本等資源以“嵌入的資源”的方式編譯到dll中。這樣被主項目引用后,就不會發生找不到資源的情況了。另外,還有一個名為Razor Generator的插件來幫助做這個事情。

            這種開發方式也有個嚴重的問題,即嚴重減慢了開發效率。每當你更改項目里的任意一點元素,包括樣式,腳本,視圖,都需要重新編譯項目才能生效。而在標準的開發方式中,這些元素都是即時生效的。原因就是在運行時,系統尋找的是dll中的資源,而不是項目里的文件。

            一般來講,用這種方式進行模塊項目發布,可能會更合適。

            MVC Portable Areas

            Portable Area disadvantages

       

            2.模擬Areas

            這個名字是我自己起的,是通過獨立的項目來模擬主項目Areas部份。在具體使用上,是將普通的Mvc項目建立到主項目的Areas文件夾下,然后手工刪除除Model,Controller,Views外的所有文件,再手工建立Areas注冊文件。這種開發方式比較巧妙的將視圖放到了Areas能找到的目錄,又是通過獨立項目的方式進行開發,基本滿足了模塊化開發的需要。

            但是這種模擬開發方式仍有一個小的瑕疵。如果一個解決方案很大,包括了多個主項目,此時就無法實現主項目共用子模塊,因為無法將一個子模塊同時放到多個項目的Areas中去。

            ASP.NET MVC 4 pluggable application modules

       

            我目前在工作中使用的是第2種開發方式。對于無法共享子模塊的問題,目前只是將代碼復制多份來解決。這顯然不是一個好的辦法,但也是沒有辦法的辦法。

            PS:如果VS支持虛擬目錄就好了。

       

            最近翻閱園子,發現菜鳥一個同學通過自定義VirtualPathProvider類實現了模塊化開發,感覺很不錯,遂仔細研讀,頗有收獲,現分享如下。

       

            3.自定義VirtualPathProvider

            這類方式的基本思路是,改變Mvc中默認尋找文件的方式,讓其到我指定的目錄查找,將找到的文件返回。但是具體實現上,我與菜鳥一個有所不同。當然,我是學習他的,是他的簡化版。

            菜鳥一個同學是重量級實現方案,其不僅重寫了尋找過程,還自定義了文件過濾機制。另外,其模塊注冊過程是在主項目中完成的。

            我的方案是輕量級實現方案,在延用Areas方式的基礎上,重寫了文件的尋找方式。模塊注冊過程是在子項目中完成的。

            下面主要介紹我的方案。菜鳥一個同學的方案可以去他的博客中研究。

            在我的案例中,MvcApplication1是主項目,MvcApplication2是模塊項目,項目文件夾與項目名同名,兩個項目文件夾放置在同級目錄。

       

            一.什么是VirtualPathProvider

            MSND上的說明是:提供了一組方法,以實現用于Web 應用程序的虛擬文件系統。

            簡單的講,當一個請求申請某個文件時,如果不存在這個文件,默認會返回404錯誤,但是這個類可以動態將別的資源作為這個資源返回回去。比如將另一個目錄下的同名或不同名文件返回,甚至動態生成一個文件然后返回。

       

            二.注冊模塊路徑

            在我們的需求中,文件不是不存在,只是不在Areas目錄下而以。所以我們要做的就是將請求的文件切換到實際目錄下然后返回。那么第一步就是要告訴系統文件的真正路徑。

            在這里我定義了IAreaVirtualPathRegistration接口,只有一個方法GetPath,就是返回模塊與路徑的對應關系

      public interface IAreaVirtualPathRegistration
      {
          List<KeyValuePair<string, string>> GetPath();
      }

            這里我沒有用字典的原因是我允許同一個模塊名有多個不同的目錄。如果使用了字典數據結構,后面的配置會覆蓋前面的配置。

            這里配置的路徑,是相對于主項目的項目文件夾的路徑。

            MvcApplication2的注冊文件如下

      public class MvcApplication2AreaVirtualPathRegistration: IAreaVirtualPathRegistration
      {
          public List<KeyValuePair<string, string>> GetPath()
          {
              var pathList = new List<KeyValuePair<string, string>>();
              pathList.Add(new KeyValuePair<string, string>("MvcApplication2", "MvcApplication2"));
      
              return pathList;
          }
      }

       

            三.自定義VirtualPathProvider

            名字就叫AreaVirtualPathProvider好了

      public class AreaVirtualPathProvider : VirtualPathProvider

       

            定義一個basePath字段,記錄主項目的物理路徑

      private readonly string basePath = Path.GetFullPath(HostingEnvironment.MapPath("~") + @"..");

       

            定義了areaVirtualPathList字段,并在靜態構造函數中獲取項目中所有注冊的模塊路徑關系

      private static List<KeyValuePair<string, string>> areaVirtualPathList = new List<KeyValuePair<string, string>>();
      
      static AreaVirtualPathProvider()
      {
          var assemblies = AppDomain.CurrentDomain.GetAssemblies();
          foreach (var assembly in assemblies)
          {
              foreach (var type in assembly.GetExportedTypes())
              {
                  if (Array.Exists(type.GetInterfaces(), t => t.Name.Equals("IAreaVirtualPathRegistration")))
                  {
                      var areaVirtualPathRegistration = assembly.CreateInstance(type.FullName) as IAreaVirtualPathRegistration;
                      foreach (var areaVirtualPath in areaVirtualPathRegistration.GetPath())
                      {
                          var key = @"/Areas/" + areaVirtualPath.Key;
                          var value = areaVirtualPath.Value;
      
                          areaVirtualPathList.Add(new KeyValuePair<string, string>(key, value));
                      }
                  }
              }
          }
      }

       

            定義了GetRealPath方法,將請求的虛擬路徑轉換為本地物理路徑,這個方法是核心方法

      private string GetRealPath(string virtualPath)
      {
          if (virtualPath.StartsWith("~"))
          {
              virtualPath = VirtualPathUtility.ToAbsolute(virtualPath);
          }
      
          foreach (var areaVirtualPath in areaVirtualPathList)
          {
              if (virtualPath.StartsWith(areaVirtualPath.Key, StringComparison.OrdinalIgnoreCase))
              {
                  var realPath = Path.Combine(basePath, virtualPath.Replace(areaVirtualPath.Key, areaVirtualPath.Value));
      
                  if (File.Exists(realPath))
                  {
                      return realPath;
                  }
              }
          }
      
          return null;
      }

            可以看到,實現其實很簡單,即將虛擬路徑中關于Areas的路徑部份替換為所配置的實際路徑。由于虛擬路徑中對于模塊項目的請求都會自動帶上/Areas/段,所以在上一步中需要為areaVirtualPath的Key的前面增加一個Areas。

       

            下面,就是重寫VirtualPathProvider的相關方法了

            首先重寫FileExists方法

      public override bool FileExists(string virtualPath)
      {
          var realPath = GetRealPath(virtualPath);
          if (realPath != null)
          {
              return true;
          }
      
          return base.FileExists(virtualPath);
      }

            可以看到,這種重寫方式,保留了默認的調用,即對于模塊項目的請求,使用自定義方式,對于主項目的請求,由于獲取的結果是null,最后還是使用默認方式。

       

            重寫GetCacheDependency方法

      public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
      {
          var realPath = GetRealPath(virtualPath);
          if (realPath != null)
          {
              var filePathList = new List<string>();
              foreach (var virtualPath1 in virtualPathDependencies)
              {
                  filePathList.Add(GetRealPath(virtualPath1.ToString()));
              }
      
              return new CacheDependency(filePathList.ToArray(), utcStart);
          }
      
          return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
      }

       

            重寫GetFileHash方法

      public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
      {
          var realPath = GetRealPath(virtualPath);
          if (realPath != null)
          {
              var filePathList = new List<string>();
              foreach (var virtualPath1 in virtualPathDependencies)
              {
                  filePathList.Add(GetRealPath(virtualPath1.ToString()));
              }
      
              return string.Join(string.Empty, filePathList.ToArray()).GetHashCode().ToString();
          }
      
          return base.GetFileHash(virtualPath, virtualPathDependencies);
      }

       

            重寫GetFile方法,這個也是核心方法

      public override VirtualFile GetFile(string virtualPath)
      {
          var realPath = GetRealPath(virtualPath);
          if (realPath != null)
          {
              var viewStream = new FileStream(realPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
              var webConfigFileStream = new FileStream(GetWebConfigFullPath(virtualPath), FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
      
              return new AreaVirtualFile(virtualPath, CorrectView(virtualPath, viewStream, webConfigFileStream));
          }
      
          return base.GetFile(virtualPath);
      }

            在談這個方法之前先說一下Mvc中的View。我們每天寫的cshtml其實只是一個半成品,框架還會為我們自動加上父類聲明,引用的命名空間等。這些文件中缺少的部份一般定義在Web.config中。

            在GetFile返回的文件中,也需要包含這些內容。

            在上面的代碼中,viewStream變量指向請求的View文件,webConfigFileStream變量指向對應的Web.config文件。Web.config文件通過GetWebConfigFullPath方法獲取

      private string GetWebConfigFullPath(string viewVirtualPath)
      {
          var realPath = Path.GetDirectoryName(GetRealPath(viewVirtualPath));
          while (realPath.Contains("\\"))
          {
              var webConfigPath = realPath + @"\Web.config";
              if (File.Exists(webConfigPath))
              {
                  return webConfigPath;
              }
      
              realPath = realPath.Substring(0, realPath.LastIndexOf('\\'));
          }
      
          return Path.GetFullPath(HostingEnvironment.MapPath("~/Views/Web.Config"));
      }

            可以看到,從cshtml所在文件夾開始逐級向上查找Web.config,如果找到則返回,如果一直沒有找到,則使用主項目的View的Web.config。

       

            拿到視圖文件和Web.config文件后,通過CorrectView方法將必要內容插入到cshtml文件中。這個方法太長,就不貼了。

       

            最后,創建一個AreaVirtualFile對象并返回。

      public class AreaVirtualFile : VirtualFile
      {
          private readonly Stream stream;
      
          public AreaVirtualFile(string virtualPath, Stream stream)
              : base(virtualPath)
          {
              this.stream = stream;
          }
      
          public override bool IsDirectory
          {
              get
              {
                  return false;
              }
          }
      
          public override Stream Open()
          {
              return stream;
          }
      }

       

            以上,就是整個方案的全部內容。

            對于這個解決方案,我有一點表示不解。我翻看了Mvc的源碼,發現其并沒有實現自己的VirtualPathProvider,那么對于我的自己實現的VirtualPathProvider,為什么GetFile方法不能使用默認實現,而必須是返回加工之后的文件呢?我功力不夠,源碼看的我很混亂,貌似其優先使用了自己的一套文件查找系統,如果找不到才使用VirtualPathProvider。

            或者,還有更優的解決方案?

       

            PS:項目實例下載

            PPS:對于.Net源碼調試的設置,可以參考這一篇

            PPPS:公司倒閉,本人失業,急求.Net相關職位,移動互聯網領域優先

            參考:

            MVC 插件式開發

            Using custom VirtualPathProvider to load embedded resource Partial Views

            如何用MEF實現Asp.Net MVC框架

            基于ASP.NET MVC3 Razor的模塊化/插件式架構實現

            自定義VirtualPathProvider映射ASP.NET MVC View

      posted @ 2014-09-08 11:50  永遠的阿哲  閱讀(4101)  評論(9)    收藏  舉報
      主站蜘蛛池模板: 国产午夜视频在线观看| 亚洲国产成人va在线观看天堂 | 久久国产成人午夜av影院| 综合激情网一区二区三区| 国日韩精品一区二区三区| 痉挛高潮喷水av无码免费| 国产一级r片内射免费视频| 国产性色av高清在线观看| 你懂的在线视频一区二区| 97久久综合亚洲色hezyo| 日韩成人性视频在线观看| 亚洲人成电影网站色mp4| 亚洲欧美日韩综合久久久| 亚洲中文字幕av天堂| 国产精品制服丝袜无码| 国产精品午夜福利片国产| 中文字幕天天躁日日躁狠狠躁免费| 乱色欧美激惰| 免费人成视频在线观看不卡| 四虎国产精品久久免费地址| 天天澡日日澡狠狠欧美老妇| 欧美午夜小视频| 久久精品丝袜高跟鞋| 国产强奷在线播放免费| 蜜臀久久综合一本av| 亚洲国产av无码综合原创国产 | 精品自拍自产一区二区三区| 男女性高爱潮免费网站| 久久天天躁狠狠躁夜夜avapp| 国产一区二区三中文字幕| 欧美z0zo人禽交另类视频| 欧美人妻在线一区二区| 亚洲爽爆av一区二区| 无码任你躁久久久久久久| 国产精品乱码一区二区三| 国产精品中文字幕久久| 国产精品中文字幕一区| 蜜桃亚洲一区二区三区四| 久久人妻精品国产| 综合图区亚洲另类偷窥| 齐河县|