自定义VirtualPathProvider映射ASP.NET MVC View

假设有多个ASP.NET MVC 应用解决方案,基于Area部署同一个站点。多个站点需要以一致的方式进行布局切换,不同Area映射View的方式不同,它们都以{AreaName}\{Views}的格式存放。相比这种访问方式,将多个Area关联的View更新到一个固定目录更便于管理,比如:App_Themes\{SkinName}\Views\{AreaName}\。自定义ViewEngine可以关联起来,还有一种方式就是自定义VirtualPathProvider。比如当请求一个/Views/Home/Index.cshtml,ASP.NET会通过VirtualPathProvider的FileExists询问路径是否存在,如果存在则会继续调用GetFile获取一个VirtualFile。我们可以将一个View的内容存放到数据库或者添加一个映射配置文件。比如对于A应用的Index.cshtml的虚拟路径:/A/Views/Home/Index.cshtml实际映射到/App_Themes/{SkinName}/Views/A/Index.cshtml,只需要继承于VirtualFile并重写Open函数。下面是一个简单示例:

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     /// 静态构造函数
 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     /// 构造函数
 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">发送方</param>
100     /// <param name="e">事件参数</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     /// 构造函数
 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     /// 打开
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 /// 启动
 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 }
原文地址:https://www.cnblogs.com/junchu25/p/2631125.html