36

我編寫了自定義VirtualFile和VirtualPathProvider實現,這些實現正在成功獲取部分視圖的嵌入式資源。使用自定義VirtualPathProvider加載嵌入資源部分視圖

然而,當我試圖使其它會產生這樣的錯誤:

The view at '~/Succeed.Web/Succeed.Web.Controls.SImporter._SImporter.cshtml' must derive from WebViewPage, or WebViewPage<TModel>.

當渲染局部視圖的常規視圖裏面,它看起來像以下:

Html.RenderPartial("~/Succeed.Web/Succeed.Web.Controls.SImporter._SImporter.cshtml"); 

是什麼導致它相信這不是局部視圖?

編輯:我發佈我的虛擬文件提供程序實現虛擬文件提供程序實現的代碼,爲任何人誰在這尋找解決方案獲取該組件工作。這個問題對於那些基於問題標題的人來說也是很好的。

ERE參考的VirtualFile實現:

public class SVirtualFile : VirtualFile 
{ 
    private string m_path; 

    public SVirtualFile(string virtualPath) 
     : base(virtualPath) 
    { 
     m_path = VirtualPathUtility.ToAppRelative(virtualPath); 
    } 

    public override System.IO.Stream Open() 
    { 
     var parts = m_path.Split('/'); 
     var assemblyName = parts[1]; 
     var resourceName = parts[2]; 

     assemblyName = Path.Combine(HttpRuntime.BinDirectory, assemblyName); 
     var assembly = System.Reflection.Assembly.LoadFile(assemblyName + ".dll"); 

     if (assembly != null) 
     { 
      return assembly.GetManifestResourceStream(resourceName); 
     } 
     return null; 
    } 
} 

的VirtualPathProvider:

public class SVirtualPathProvider : VirtualPathProvider 
{ 
    public SVirtualPathProvider() 
    { 

    } 

    private bool IsEmbeddedResourcePath(string virtualPath) 
    { 
     var checkPath = VirtualPathUtility.ToAppRelative(virtualPath); 
     return checkPath.StartsWith("~/Succeed.Web/", StringComparison.InvariantCultureIgnoreCase); 
    } 

    public override bool FileExists(string virtualPath) 
    { 
     return IsEmbeddedResourcePath(virtualPath) || base.FileExists(virtualPath); 
    } 

    public override VirtualFile GetFile(string virtualPath) 
    { 
     if (IsEmbeddedResourcePath(virtualPath)) 
     { 
      return new SVirtualFile(virtualPath); 
     } 
     else 
     { 
      return base.GetFile(virtualPath); 
     } 
    } 

    public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) 
    { 
     if (IsEmbeddedResourcePath(virtualPath)) 
     { 
      return null; 
     } 
     else 
     { 
      return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); 
     } 
    } 
} 

,當然還有,別忘了在你的項目的Global.asax文件來註冊這個新的供應商在Application_Start()事件

System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(new SVirtualPathProvider()); 

回答

44

因爲現在你是Servi大街從某個未知位置查看您的視圖,不再有~/Views/web.config文件適用於您的剃鬚刀視圖(<pages pageBaseType="System.Web.Mvc.WebViewPage">),並指示您的剃鬚刀視圖的基準類別。所以你可以在每個嵌入視圖的頂部添加@inherits指令來表示基類。

@inherits System.Web.Mvc.WebViewPage 
@model ... 
+0

非常感謝。我唯一的遺憾是我只有一個投票權。 = P Up投票回答這個問題 –

+3

@ darin Dimitrov我不認爲你知道我可以用來鼓勵intellisense將它視爲我的dll內的視圖嗎?現在,我對intellisense的支持非常少,我在我的dll –

+0

@MatthewCox中放置了一些視圖,對視圖中的Intellisense我不太瞭解。很久以前,我停止依靠它。如果該文件具有'.cshtml'擴展名,你不會得到Intellisense嗎? –

6

我用OP的答案作爲基礎,但擴展了一下,並在我的解決方案中引入了問題的答案。

這似乎是一個有些常見問題,因此我沒有看到完整的答案,所以我認爲分享我的工作解決方案可能會有幫助。

我從數據庫加載我的資源,並將它們緩存在默認緩存(System.Web.Caching.Cache)中。

我最終做的是在我用來查找資源的KEY上創建一個自定義CacheDependency。這樣,每當我的其他代碼使緩存無效(編輯等)時,該密鑰的緩存依賴性將被刪除,並且VirtualPathProvider會使其緩存失效,並重新加載VirtualFile。

我還更改了代碼,以便它自動預置繼承語句,以便它不需要存儲在我的數據庫資源中,並且還自動預先添加一些默認使用語句,因爲此「視圖」未通過正常的渠道,所以任何默認包括在你的web.config或viewstart是不可用的。

CustomVirtualFile:

public class CustomVirtualFile : VirtualFile 
{ 
    private readonly string virtualPath; 

    public CustomVirtualFile(string virtualPath) 
     : base(virtualPath) 
    { 
     this.virtualPath = VirtualPathUtility.ToAppRelative(virtualPath); 
    } 

    private static string LoadResource(string resourceKey) 
    { 
     // Load from your database respository or whatever here... 
     // Note that the caching is disabled for this content in the virtual path 
     // provider, so you must cache this yourself in your repository. 

     // My implementation using my custom service locator that sits on top of 
     // Ninject 
     var contentRepository = FrameworkHelper.Resolve<IContentRepository>(); 

     var resource = contentRepository.GetContent(resourceKey); 

     if (String.IsNullOrWhiteSpace(resource)) 
     { 
      resource = String.Empty; 
     } 

     return resource; 
    } 

    public override Stream Open() 
    { 
     // Always in format: "~/CMS/{0}.cshtml" 
     var key = virtualPath.Replace("~/CMS/", "").Replace(".cshtml", ""); 

     var resource = LoadResource(key); 

     // this automatically appends the inherit and default using statements 
     // ... add any others here you like or append them to your resource. 
     resource = String.Format("{0}{1}", "@inherits System.Web.Mvc.WebViewPage<dynamic>\r\n" + 
              "@using System.Web.Mvc\r\n" + 
              "@using System.Web.Mvc.Html\r\n", resource); 

     return resource.ToStream(); 
    } 
} 

CustomVirtualPathProvider:

public class CustomVirtualPathProvider : VirtualPathProvider 
{ 
    private static bool IsCustomContentPath(string virtualPath) 
    { 
     var checkPath = VirtualPathUtility.ToAppRelative(virtualPath); 
     return checkPath.StartsWith("~/CMS/", StringComparison.InvariantCultureIgnoreCase); 
    } 

    public override bool FileExists(string virtualPath) 
    { 
     return IsCustomContentPath(virtualPath) || base.FileExists(virtualPath); 
    } 

    public override VirtualFile GetFile(string virtualPath) 
    { 
     return IsCustomContentPath(virtualPath) ? new CustomVirtualFile(virtualPath) : base.GetFile(virtualPath); 
    } 

    public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) 
    { 
     if (IsCustomContentPath(virtualPath)) 
     { 
      var key = VirtualPathUtility.ToAppRelative(virtualPath); 

      key = key.Replace("~/CMS/", "").Replace(".cshtml", ""); 

      var cacheKey = String.Format(ContentRepository.ContentCacheKeyFormat, key); 

      var dependencyKey = new String[1]; 
      dependencyKey[0] = string.Format(cacheKey); 

      return new CacheDependency(null, dependencyKey); 
     } 

     return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); 
    } 

    public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies) 
    { 
     if (IsCustomContentPath(virtualPath)) 
     { 
      return virtualPath; 
     } 

     return base.GetFileHash(virtualPath, virtualPathDependencies); 
    } 
} 

希望這有助於!

0

我重視OP中的信息以及Darin Dimitrov的回答,即創建一個用於跨項目共享MVC組件的simple prototype。雖然這些非常有幫助,但我還是遇到了一些額外的障礙,這些障礙在原型中處理,例如使用@ model的共享視圖。

相關問題