zoukankan      html  css  js  c++  java
  • Asp.Net MVC 项目预编译 View

    最近做项目是遇到一个问题,在我们的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,最终运行结果:

    最终运行成功。在这里最好的解决方案还是用强类型,此文章只是从技术的角度来分析问题解决问题,仅供大家参考。欢迎大家拍砖!

  • 相关阅读:
    java——注解Annotation
    java——maven
    sklearn——回归评估指标
    java——单例模式
    java——极简handler机制
    java——为什么要有接口?和抽象类有什么不一样?
    java——cmd命令编译带包名的源程序
    [loj 2478][luogu P4843]「九省联考 2018」林克卡特树
    「线性基」学习小结
    FOI 冬令营 Day6
  • 原文地址:https://www.cnblogs.com/majiang/p/2782254.html
Copyright © 2011-2022 走看看