MVC 5 中的 VirtualPathProvider
我似乎無法讓自定義 VirtualPathProvider 在 asp.net MVC 5 中工作。
FileExists 方法返回 true,但不會呼叫 GetFile 方法。我相信這是因為 IIS 接管了請求並且不讓 .NET 處理它。
我已嘗試設置 RAMMFAR 並創建自定義處理程序,如在此解決方案中https://stackoverflow.com/a/12151501/801189但仍然沒有運氣。我收到錯誤 404。
我的自定義提供商:
public class DbPathProvider : VirtualPathProvider { public DbPathProvider() : base() { } private static bool IsContentPath(string virtualPath) { var checkPath = VirtualPathUtility.ToAppRelative(virtualPath); return checkPath.StartsWith("~/CMS/", StringComparison.InvariantCultureIgnoreCase); } public override bool FileExists(string virtualPath) { return IsContentPath(virtualPath) || base.FileExists(virtualPath); } public override VirtualFile GetFile(string virtualPath) { return IsContentPath(virtualPath) ? new DbVirtualFile(virtualPath) : base.GetFile(virtualPath); } public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) { return null; } public override String GetFileHash(String virtualPath, IEnumerable virtualPathDependencies) { return Guid.NewGuid().ToString(); } }我的自定義虛擬文件:
public class DbVirtualFile : VirtualFile { public DbVirtualFile(string path): base(path) { } public override System.IO.Stream Open() { string testPage = "This is a test!"; return new System.IO.MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(testPage)); } }我嘗試使用的 web.config 處理程序,但沒有成功。它目前給出錯誤 500 :
<system.webServer> <modules runAllManagedModulesForAllRequests="true"> <remove name="FormsAuthenticationModule" /> </modules> <handlers> <add name="ApiURIs-ISAPI-Integrated-4.0" path="/CMS/*" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="runtimeVersionv4.0" /> </handlers>如果我嘗試導航到 site.com/CMS/Home/Index,則會呼叫 FileExists 方法,但奇怪的是,virtualPath 參數只接收 ~/CMS/Home。
添加斷點,似乎對於 url site.com/CMS/Home/Index,FileExists 方法不斷被重複呼叫。這可能會導致無限遞歸,從而導致內部伺服器錯誤。
它實際上與 IIS 無關,實際上是對事件順序的混淆。似乎我不明白路由操作方法必須返回一個視圖,VirtualPathProvider 將嘗試解析,而不是直接轉到 VirtualPathProvider。
我使用單個 GetPage 操作創建了一個名為 ContentPagesController 的簡單控制器:
public class ContentPagesController : Controller { [HttpGet] public ActionResult GetPage(string pageName) { return View(pageName); } }然後我設置我的路由來提供虛擬頁面:
routes.MapRoute( name: "ContentPageRoute", url: "CMS/{*pageName}", defaults: new { controller = "ContentPages", action = "GetPage" }, constraints: new { controller = "ContentPages", action = "GetPage" } );在我註冊路由之前,我在 globals.asax.cs 中註冊了我的自定義 VirtualPathProvider。
現在假設我的數據庫中有一個帶有相對 url /CMS/Home/AboutUs 的頁面。pageName 參數的值為 Home/AboutUs,返回 View() 呼叫將指示 VirtualPathProvider 查找文件 ~/Views/ContentPages/Home/AboutUs.cshtml 的變體。
它將尋找的一些變化包括:
~/Views/ContentPages/Home/AboutUs.aspx ~/Views/ContentPages/Home/AboutUs.ascx ~/Views/ContentPages/Home/AboutUs.vbhtml您現在需要做的就是使用數據庫查找或類似方法檢查傳遞給 GetFiles 方法的 virtualPath。這是一個簡單的方法:
private bool IsCMSPath(string virtualPath) { return virtualPath == "/Views/ContentPages/Home/AboutUs.cshtml" || virtualPath == "~/Views/ContentPages/Home/AboutUs.cshtml"; } public override bool FileExists(string virtualPath) { return IsCMSPath(virtualPath) || base.FileExists(virtualPath); } public override VirtualFile GetFile(string virtualPath) { if (IsCMSPath(virtualPath)) { return new DbVirtualFile(virtualPath); } return base.GetFile(virtualPath); }自定義虛擬文件將在 GetFile 方法中生成並返回給瀏覽器。
最後,可以創建一個自定義視圖引擎來提供發送到 VirtualPathProvider 的不同虛擬視圖路徑。
希望這可以幫助。