最近做項目是遇到一個問題,在我們的view中經常遇到一些匿名類型對象,然后在通過RenderPartial輸出這些對象。
還是舉個例子吧,有3個view Index.cshtml、Test.cshtml、Test2.cshtml
它們的層次結構如圖:
它們的代碼如下:
Index.cshtml
@{ Layout = null; var obj = new[] { new {name="majiang",age=27}, new {name="luyang",age=26} }; } <!DOCTYPE html> <html> <head> <title>Index</title> </head> <body> <div> @{ <h2>@(obj.GetType().Assembly.Location)</h2> Html.RenderPartial("Test", obj); Html.RenderPartial("Test2", obj); } </div> </body> </html>
Test.cshtml 和Test2.cshtml
@{ Layout = null; var obj = this.Model; var a = new {name="majiang",age=27}; <h2>@(a.GetType().Assembly.Location)</h2> foreach (var item in obj) { <h3>@item.name</h3> <h3>@item.age</h3> } }
運行結果Test2.cshtml有錯誤 提示:
為什么在test里面是對的而到了test2就錯了,這2個view只是路徑不同,對就是路徑不同導致生成dll的路徑也不同嗎?讓我們來證實一下
首先把 test2里面的代碼修改為:
@{
Layout = null;
var obj = this.Model;
var a = new { name = "majiang", age = 27 };
<h2>@(a.GetType().Assembly.Location)</h2>
@* foreach (var item in obj)
{
<h3>@item.name</h3>
<h3>@item.age</h3>
}*@
}
運行結果如圖:
很明顯test和index在同一目錄下,它們生成的匿名類型也在同一個dll中,而test2 不再這一目錄中那么生成的匿名類型也不再同一dll中。
為什么會這樣了,讓我們來看看源代碼吧
在BuildManagerCompiledView類的 public void Render(ViewContext viewContext, TextWriter writer)方法中有
Type type = BuildManager.GetCompiledType(ViewPath);
而BuildManager的定義是:
internal IBuildManager BuildManager {
get {
if (_buildManager == null) {
_buildManager = new BuildManagerWrapper();
}
return _buildManager;
}
set {
_buildManager = value;
}
}
再讓我們看看BuildManagerWrapper類
internal sealed class BuildManagerWrapper : IBuildManager {
bool IBuildManager.FileExists(string virtualPath) {
return BuildManager.GetObjectFactory(virtualPath, false) != null;
}
Type IBuildManager.GetCompiledType(string virtualPath) {
return BuildManager.GetCompiledType(virtualPath);
}
ICollection IBuildManager.GetReferencedAssemblies() {
return BuildManager.GetReferencedAssemblies();
}
Stream IBuildManager.ReadCachedFile(string fileName) {
return BuildManager.ReadCachedFile(fileName);
}
Stream IBuildManager.CreateCachedFile(string fileName) {
return BuildManager.CreateCachedFile(fileName);
}
}
看來view的編譯取決於系統的BuildManager,它既是程序集內部類同時也是密封類要擴展它不太現實。
那么這個如何解決了?既然我們不能讓所有view動態編譯到相同的dll中,那么如果把這幾個view預編譯能否編譯到當前項目dll中了?(維護比較麻煩因為修改view就會更新view所在項目的dll),是否可以解決了?理論是可行的讓我們試試吧。
首先讓我們安裝
Razor Generator
其次.使用NuGet安裝PrecompiledMvcViewEngine。
修改view屬性中的自定義工具為RazorGenerator,修改如圖
最后我們還原test2,最終運行結果:
最終運行成功。在這里最好的解決方案還是用強類型,此文章只是從技術的角度來分析問題解決問題,僅供大家參考。歡迎大家拍磚!