Razor ViewEngine缓存渲染的HTML吗



我有一个两级菜单项:我有一份部门列表,每个部门都有一份商店列表。

我有一个菜单PartialView,它遍历Model(部门(并构建菜单:

@model IEnumerable<Department>
<ul>
@foreach (var department in Model)
{
<li>
<a href="#">@Model.DepartmentName</a>
<ul>
@foreach (var store in department.Stores)
{
<li><a href="some-url">@store.StoreName</a></li>
}
</ul>
</li>
}
</ul>

这就是我在_layout.cshtml:中称菜单PartialView的方式

@Html.Partial("Shared/_Menu", MyApplicationCache.departments) 

正如您所看到的,我正在将相同的模型(从缓存(传递给所有请求的PartialView。

Razor ViewEngine是否有一个内部缓存系统来识别该视图已经为此模型构建(符合HTML字符串(?还是在每个请求上重新呈现(重新编译(PartialView?

假设Controller或其操作方法上没有应用任何OutputCacheAttribute,则PartialView会在每次请求时重新呈现。

如果需要输出缓存,则需要通过OutputCacheAttribute明确设置,请参阅文档。

您可以通过输出DateTime(例如通过如下所示的菜单项(来轻松地检查这一点
在每次请求时,它都会显示一个新值,以证明它已被重新渲染。

<li><a href="#">@DateTime.Now</a></li>

完整菜单:

@model IEnumerable<Department>
<ul>
@foreach (var department in Model)
{
<li>
<a href="#">@Model.DepartmentName</a>
<ul>
<li><a href="#">@DateTime.Now</a></li>
@foreach (var store in department.Stores)
{
<li><a href="some-url">@store.StoreName</a></li>
}                
</ul>
</li>
}
</ul>

重新渲染和重新编译在ASP.Net MVC中非常不同。虽然这里的大多数答案都是正确的,但视图只编译一次(除了在调试模式下,每次都会编译它,这样您就可以更改视图、点击刷新并查看更改,或者如果生产中文件的时间戳发生了更改(。它被编译为从WebViewpage(没有ViewModel(或WebViewPage<T>(具有类型为T的ViewModel(派生的运行时类。

该类为所需的每个视图实例化(因此,如果多次使用相同的分部,则每次都必须实例化(,填充模型,并调用execute((方法来创建/流式传输HTML到客户端。视图永远无法按模型缓存,因为这样做太复杂了,相反,MVC团队选择允许按控制器方法配置缓存,而不是按WebViewPage配置缓存。

@ErikPhilips,非常感谢-所以视图只编译一次(无论我们是否使用OutputCache(?它是将运行时类渲染为HtmlString的execute方法,而渲染将从缓存中受益?

有点像,但它比这更高级、更容易、更复杂。

高级-输出缓存基于控制器方法。因此,如果输出缓存配置确定调用可以使用缓存版本,则永远不会调用控制器方法。这就是巨大的性能增益所在。想象一下,没有对DB/外部API调用的调用,就没有必要了。您可以配置缓存,使其在看到id=1时缓存30分钟。现在,任何通过授权和id=1调用该方法的人都会获得缓存的字符串/html。

更简单-你把你的OuputCacheAttribute放在一个方法上,配置它,你就完成了。配置起来非常简单。

复杂-缓存可能更复杂,因为您可以使用Html.Action()(如果您的部分不需要布局,则为Html.Partial()(或首选Html.RenderAction();(如果您不需要布局则为Html.RenderPartial()(来渲染其他控制器方法。曾经有一个甜甜圈缓存问题(推荐阅读(,但这个问题已经解决了很长时间。

这个问题有一个很好的答案,证明PartialViews没有被缓存,评论中建议的这个链接解释了如何将[OutputCache]用于partialView-这可以与Html.Action()/Html.RenderAction()一起使用,并将partialView渲染为[ChildAction]

将PartialView缓存为子操作是有意义的,但我不想将我的菜单呈现为[ChildAction],因为我不想单独调用来显示菜单,所以这就是我最终要做的:

在应用程序启动时,我使用RazorEngine将PartialView渲染为HtmlString,并将HtmlString保存在静态变量(缓存(中。

public static class MenuCache
{
private static readonly MvcHtmlString _menuMvcHtmlString;
static MenuCache()
{
using (var context = ApplicationDbContext.Create())
using (var razorEngine = RazorEngineService.Create(new TemplateServiceConfiguration()))
{
var repository = new MyRepository(context);
var departments = repository.GetDepartments();
// use razorEngine to render menu partial view into html string 
// keep the htmlString in cache: _menuMvcHtmlString
string menuPartialView = File.ReadAllText(HostingEnvironment.MapPath("~/Views/Shared/_Menu.cshtml"));
string menuHtmlString = razorEngine.RunCompile(menuPartialView, "menuKey", null, departments);
_menuMvcHtmlString = new MvcHtmlString(menuHtmlString);
}
}
public static MvcHtmlString GetMenuHtmlString()
{
return _menuMvcHtmlString;
}
}

我还创建了一个自定义的HtmlHelper方法,它将返回菜单的HtmlString:

public static class HtmlHelperExtensions
{
public static MvcHtmlString MyMenu(this HtmlHelper html)
{
return MenuCache.GetMenuHtmlString();
}
}

现在,在我的布局页面中,我可以使用定制的HtmlHelper来显示菜单:

@Html.MyMenu()

相关内容

  • 没有找到相关文章

最新更新