首页 文章

ASP.NET MVC视图引擎解析序列

提问于
浏览
10

我创建了一个简单的ASP.NET MVC 1.0版应用程序 . 我有一个ProductController,它有一个动作索引 . 在视图中,我在Product子文件夹下创建了相应的Index.aspx .

然后我引用了Spark dll并在同一Product视图文件夹下创建了Index.spark . Application_Start看起来像

protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);

        ViewEngines.Engines.Clear();
        ViewEngines.Engines.Add(new Spark.Web.Mvc.SparkViewFactory());

        ViewEngines.Engines.Add(new WebFormViewEngine());

    }

我的期望是,由于Spark引擎在默认WebFormViewEngine之前注册,当浏览Product controller中的Index操作时,应该使用Spark引擎,并且WebFormViewEngine应该用于所有其他URL .

但是,测试显示Product控制器的Index操作也使用WebFormViewEngine .

如果我注释掉WebFormViewEnginer的注册(代码中的最后一行),我可以看到Index动作由Spark引擎呈现,其余的URL生成错误(因为defualt引擎已经消失),它证明了我所有的Spark代码是正确的 .

现在我的问题是视图引擎是如何解决的?为什么注册序列不生效?

2 回答

  • 18

    注册视图引擎的顺序并不重要(很多) . 相反,视图引擎采用一组 ViewLocationFormats ,如果特定视图路径符合格式化名称,则将使用该引擎 . 只有当您的格式存在冲突时,注册顺序才会起作用 .

    在spark的情况下,视图应该具有 .spark 扩展名 . WebFormViewEngine 将通过 .aspx.ascx 扩展回复任何内容 . 当然,如上所述,您可以通过更改提供给各个视图引擎的 ViewLocationFormats 来覆盖任何此类操作 .


    Updated:

    我看了一下 SparkViewFactoryWebFormViewEngine (或者更具体地来说, VirtualPathProviderViewEngine ,后者来自)的来源,我可以告诉你为什么你会看到这种奇怪的行为 .

    首先, ViewEngineCollection 类中的 Find 方法的工作原理如下(简化):

    foreach (IViewEngine engine in Items) {
        // Query engine for cached view
    }
    
    foreach (IViewEngine engine in Items) {
        // Query engine for uncached view
    }
    

    换句话说,在诉诸非缓存模式之前,它总是会尝试在 any 引擎中找到缓存视图 .

    各个视图引擎实现此方法的方式是 FindView 方法的第二个重载,该方法采用名为 useCachebool 参数 .

    However ,这里的一切都变得奇怪 - VirtualPathProviderViewEngineSparkViewEngineuseCache 论证的含义有着截然不同的看法 . 这里有太多代码要重新发布,但基本思路是:

    • 如果 useCachetrueSparkViewFactory 将在缓存中显示 only . 如果它没有找到任何东西,它会自动返回"cache miss result" - 即没有 . 另一方面,如果 useCachefalse ,它根本不会查看缓存,它将跳过缓存检查步骤并通过正常运动来解析并创建实际视图 .

    • 另一方面,如果 useCachetrueVirtualPathProviderViewEngine 会在缓存中查找,如果它在缓存中找不到该视图, it goes off and creates a new one and adds that to the cache.

    这两种方法都适用于 ViewEngineCollection 执行搜索的方式 .

    • 在spark的情况下,它在视图引擎的第一次迭代中“未命中”,但在第二次迭代时“命中”,之后视图被添加到缓存中 . 没问题 .

    • VirtualPathProviderViewEngine 的情况下,它在内部"misses"但在第一次迭代时仍然返回"hit",此时视图现在被缓存 .

    所以你应该能够看到问题出在哪里 . VirtualPathProviderViewEngine 似乎仅优先于 SparkViewEngine ,因为前者总是在 first (缓存)迭代上成功,但Spark仅在 second (未缓存)迭代上成功 .

    用简单的英语,Spark确实首先被问到,但回复:“不,我没有那个视图 yet . 试着没有缓存而是 . ” WebForms被问到第二,但自动说“我 didn't 有那种观点,但无论如何我去为你做了一个,这里是 . ” . 从那时起, WebFormViewEngine 总是获得优先权,因为它有缓存视图而Spark没有 .


    总结:Spark is 获得优先权,但由于Spark处理 useCache 参数的方式有些怪癖,当Web Form引擎同时处于活动状态时,它仍然处于灰尘状态 . 根据您的观点,WebForm过于热切或Spark很懒惰 .

    简单地说,解决方案是 not to have conflicting views! 如果您已经注册了多个视图引擎,那么您应该处理任何可以由两个/两个处理的视图名称他们是 undefined behaviour .

  • 1

    嗯...没有 - 当useCache为true时,所有应有的尊重webforms都不会执行任何超出缓存检查的操作 . 与Spark相同 .

    实际上 - 我认为有人可能会移动我的奶酪...... Spark可能会在useCache == true pass期间添加一个怪癖导致错误的缓存缺失 . 如果这是真的,那么与应用于该参数的不同规则相比,它更像是一个错误 .


    更新:

    我最初看的是MVC 2 - 这就是为什么我暗示@Aaronaught的结论不正确 . MVC 2不会在第一次传递中返回一个视图,其中useCache == true,这与MVC 1.0中的不同将解析和填充 .

    因此,ASP.NET MVC 1.0和ASP.NET MVC 2的实现方式之间存在差异 . Spark和MVC 2对useCache标志的处理方式相同,它们注册的顺序将赋予它们优先权 .

相关问题