自定義VirtualPathProvider映射ASP.NET MVC View
假設(shè)有多個(gè)ASP.NET MVC 應(yīng)用解決方案,基于Area部署同一個(gè)站點(diǎn)。多個(gè)站點(diǎn)需要以一致的方式進(jìn)行布局切換,不同Area映射View的方式不同,它們都以{AreaName}\{Views}的格式存放。相比這種訪問(wèn)方式,將多個(gè)Area關(guān)聯(lián)的View更新到一個(gè)固定目錄更便于管理,比如:App_Themes\{SkinName}\Views\{AreaName}\。自定義ViewEngine可以關(guān)聯(lián)起來(lái),還有一種方式就是自定義VirtualPathProvider。比如當(dāng)請(qǐng)求一個(gè)/Views/Home/Index.cshtml,ASP.NET會(huì)通過(guò)VirtualPathProvider的FileExists詢問(wèn)路徑是否存在,如果存在則會(huì)繼續(xù)調(diào)用GetFile獲取一個(gè)VirtualFile。我們可以將一個(gè)View的內(nèi)容存放到數(shù)據(jù)庫(kù)或者添加一個(gè)映射配置文件。比如對(duì)于A應(yīng)用的Index.cshtml的虛擬路徑:/A/Views/Home/Index.cshtml實(shí)際映射到/App_Themes/{SkinName}/Views/A/Index.cshtml,只需要繼承于VirtualFile并重寫Open函數(shù)。下面是一個(gè)簡(jiǎn)單示例:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <map> 3 <view virtualPath="" mapTo="" /> 4 </map>
1 /// <summary> 2 /// 視圖映射 3 /// </summary> 4 [XmlType(TypeName = "view")] 5 public class ViewMap 6 { 7 /// <summary> 8 /// 虛擬路徑 9 /// </summary> 10 [XmlAttribute(AttributeName = "virtualPath")] 11 public String VirtualPath { get; set; } 12 13 /// <summary> 14 /// 映射到 15 /// </summary> 16 [XmlAttribute(AttributeName = "mapTo")] 17 public String MapTo { get; set; } 18 }
1 /// <summary> 2 /// 視圖映射路徑提供器 3 /// </summary> 4 public sealed class ViewMapPathProvider : VirtualPathProvider 5 { 6 /// <summary> 7 /// 序列化提供器 8 /// </summary> 9 private static readonly XmlSerializer SerializeProvider; 10 11 /// <summary> 12 /// 靜態(tài)構(gòu)造函數(shù) 13 /// </summary> 14 static ViewMapPathProvider() 15 { 16 SerializeProvider = new XmlSerializer(typeof(List<ViewMap>), new XmlRootAttribute("map")); 17 } 18 19 private IDictionary<String, ViewMap> m_views; 20 private FileSystemWatcher m_fileWatcher; 21 22 /// <summary> 23 /// 構(gòu)造函數(shù) 24 /// </summary> 25 /// <param name="xmlPath">文件路徑</param> 26 public ViewMapPathProvider(String xmlPath) 27 { 28 if (String.IsNullOrEmpty(xmlPath)) 29 throw new ArgumentException("xmlPath不能為空"); 30 31 if (!File.Exists(xmlPath)) 32 throw new FileNotFoundException(String.Format("文件{0}不存在", xmlPath)); 33 34 this.XmlPath = xmlPath; 35 36 m_fileWatcher = new FileSystemWatcher(Path.GetDirectoryName(xmlPath)); 37 m_fileWatcher.Changed += new FileSystemEventHandler(OnFileChanged); 38 } 39 40 /// <summary> 41 /// 文件路徑 42 /// </summary> 43 public String XmlPath { get; private set; } 44 45 /// <summary> 46 /// 視圖集合 47 /// </summary> 48 public IDictionary<String, ViewMap> Views 49 { 50 get 51 { 52 if (m_views == null) 53 { 54 using (TextReader textReader = new StreamReader(this.XmlPath, true)) 55 { 56 List<ViewMap> views = SerializeProvider.Deserialize(textReader) as List<ViewMap>; 57 58 m_views = views.ToDictionary(p => p.VirtualPath); 59 } 60 } 61 62 return m_views; 63 } 64 } 65 66 /// <summary> 67 /// 文件是否存在 68 /// </summary> 69 /// <param name="virtualPath">虛擬路徑</param> 70 /// <returns>是否存在</returns> 71 public override Boolean FileExists(String virtualPath) 72 { 73 if (this.Views.ContainsKey(virtualPath)) 74 return true; 75 76 return base.FileExists(virtualPath); 77 } 78 79 /// <summary> 80 /// 獲取文件 81 /// </summary> 82 /// <param name="virtualPath">虛擬路徑</param> 83 /// <returns>虛擬文件</returns> 84 public override VirtualFile GetFile(String virtualPath) 85 { 86 if (this.Views.ContainsKey(virtualPath)) 87 { 88 ViewMap viewMap = this.Views[virtualPath]; 89 90 return new ViewMapFile(virtualPath, viewMap); 91 } 92 93 return base.GetFile(virtualPath); 94 } 95 96 /// <summary> 97 /// 文件變化 98 /// </summary> 99 /// <param name="sender">發(fā)送方</param> 100 /// <param name="e">事件參數(shù)</param> 101 private void OnFileChanged(Object sender, FileSystemEventArgs e) 102 { 103 if (String.Equals(e.FullPath, this.XmlPath, StringComparison.CurrentCultureIgnoreCase)) 104 m_views = null; 105 } 106 }
1 /// <summary> 2 /// 視圖映射文件 3 /// </summary> 4 public class ViewMapFile : VirtualFile 5 { 6 /// <summary> 7 /// 構(gòu)造函數(shù) 8 /// </summary> 9 /// <param name="virtualPath">虛擬路徑</param> 10 /// <param name="viewMap">視圖映射</param> 11 public ViewMapFile(String virtualPath, ViewMap viewMap) 12 : base(virtualPath) 13 { 14 this.ViewMap = viewMap; 15 } 16 17 /// <summary> 18 /// 視圖映射 19 /// </summary> 20 public ViewMap ViewMap { get; private set; } 21 22 /// <summary> 23 /// 打開(kāi) 24 /// </summary> 25 /// <returns>流</returns> 26 public override Stream Open() 27 { 28 return new FileStream(this.ViewMap.MapTo, FileMode.Open, FileAccess.Read); 29 } 30 }
1 /// <summary> 2 /// 啟動(dòng) 3 /// </summary> 4 protected void Application_Start() 5 { 6 AreaRegistration.RegisterAllAreas(); 7 8 RegisterGlobalFilters(GlobalFilters.Filters); 9 RegisterRoutes(RouteTable.Routes); 10 11 String xmlPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\ViewMap.xml"); 12 HostingEnvironment.RegisterVirtualPathProvider(new ViewMapPathProvider(xmlPath)); 13 }

浙公網(wǎng)安備 33010602011771號(hào)