我在使用 FindPartialView() 时遇到了一些奇怪的性能问题,为了调试我有以下在发布模式下运行的代码:
var startTime = DateTime.Now;
var view = this.BaseViewEngine.FindPartialView(context, proposedViewPath, useCache);
var timeTaken = DateTime.Now - startTime;
this.log.Write(string.Format("FindPartialView Result: useCache='{0}' proposedViewPath='{1}' TimeTakenMS={2}ms", useCache, proposedViewPath, timeTaken.TotalMilliseconds));
其中 BaseViewEngine 是在 Application_Start 创建的 WebFormViewEngine 的一个实例。
当不在缓存中时,它会生成类似的日志
FindPartialView Result: useCache='True' proposedViewPath='~/Controls/Navigation/TopNavigation.ascx' TimeTakenMs=0ms
FindPartialView Result: useCache='False' proposedViewPath='~/Controls/Navigation/TopNavigation.ascx' TimeTakenMs=1607ms
FindPartialView Result: useCache='True' proposedViewPath='~/Controls/Navigation/FooterMenu.ascx' TimeTakenMs=0ms
FindPartialView Result: useCache='False' proposedViewPath='~/Controls/Navigation/FooterMenu.ascx' TimeTakenMs=0ms
FindPartialView Result: useCache='True' proposedViewPath='~/Controls/Navigation/FooterMenuItem.ascx' TimeTakenMs=0ms
FindPartialView Result: useCache='False' proposedViewPath='~/Controls/Navigation/FooterMenuItem.ascx' TimeTakenMs=1279ms
当它是:
FindPartialView Result: useCache='True' proposedViewPath='~/Controls/Navigation/TopNavigation.ascx' TimeTakenMs=0ms
FindPartialView Result: useCache='True' proposedViewPath='~/Controls/Navigation/FooterMenu.ascx' TimeTakenMs=0ms
FindPartialView Result: useCache='True' proposedViewPath='~/Controls/Navigation/FooterMenuItem.ascx' TimeTakenMs=0ms
这不会那么糟糕,但我们遇到的问题是它似乎经常随机地从缓存中删除项目(77 个日志条目中的 17 个仅相隔几分钟)。因为它在缓存中找不到它,所以它使用 useCache=false 运行,这通常需要很长的时间(我们已经记录了它需要超过 4 秒)。
首先,有人知道为什么需要这么长时间吗?它不是在调试模式下编译的,我们给它一个绝对路径,所以它不应该搜索它。我尝试给它完整的文件系统路径(例如 C:\Web\Controls\Navigation\FooterItem.ascx),但它根本无法工作。
其次,有没有办法让它使用自定义视图缓存,这样至少我们可以确保项目保持缓存?
谢谢!
编辑:好的,到目前为止我已经得到了这个,它似乎适用于我们的使用模式,有人能想到一个不这样做的好理由吗?
/// <summary>
/// Optimised WebFormViewEngine to fix performance issue with FindView / FindPartialView
/// </summary>
public class FastWebFormViewEngine : WebFormViewEngine
{
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
// If absolute path then no need to search for the view
return partialViewName.StartsWith("~")
? new ViewEngineResult(this.CreatePartialView(controllerContext, partialViewName), this)
: base.FindPartialView(controllerContext, partialViewName, useCache);
}
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
// If absolute path then no need to search for the view
return viewName.StartsWith("~") && (string.IsNullOrEmpty(masterName) || masterName.StartsWith("~"))
? new ViewEngineResult(this.CreateView(controllerContext, viewName, masterName), this)
: base.FindView(controllerContext, viewName, masterName, useCache);
}
}