我有一个带有最新消息列表的小部件,如何仅缓存小部件输出?OutputCache 模块缓存整个页面和匿名用户,但实际上我只需要缓存一个形状输出。这里有什么解决方案?
2 回答
缓存对象本身不是一个好主意Shape
,但是您可以从 a 捕获 HTML 输出Shape
并缓存它。
每个果园Shape
都有一个对应的对象,称为Metadata
. 除其他外,此对象包含一些可以在Shape
显示时或显示后运行的事件处理程序。通过使用这些事件处理程序,可以缓存Shape
第一次调用驱动程序时的输出。然后对于未来对驱动程序的调用,我们可以显示输出的缓存副本,而不是运行驱动程序或模板渲染的昂贵部分。
例子:
using System.Web;
using DemoModule.Models;
using Orchard.Caching;
using Orchard.ContentManagement.Drivers;
using Orchard.DisplayManagement.Shapes;
namespace DemoModule.Drivers {
public class MyWidgetPartDriver : ContentPartDriver<MyWidgetPart> {
private readonly ICacheManager _cacheManager;
private readonly ISignals _signals;
public MyWidgetPartDriver(
ICacheManager cacheManager,
ISignals signals
) {
_cacheManager = cacheManager;
_signals = signals;
}
public class CachedOutput {
public IHtmlString Output { get; set; }
}
protected override DriverResult Display(MyWidgetPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_MyWidget", () => {
// The cache key. Build it using whatever is needed to differentiate the output.
var cacheKey = /* e.g. */ string.Format("MyWidget-{0}", part.Id);
// Standard Orchard cache manager. Notice we get this object by reference,
// so we can write to its field to save our cached HTML output.
var cachedOutput = _cacheManager.Get(cacheKey, ctx => {
// Use whatever signals are needed to invalidate the cache.
_signals.When(/* e.g. */ "ExpireCache");
return new CachedOutput();
});
dynamic shape;
if (cachedOutput.Output == null) {
// Output has not yet been cached, so we are going to build the shape normally
// and then cache the output.
/*
... Do normal (potentially expensive) things (call DBs, call services, etc.)
to prep shape ...
*/
// Create shape object.
shape = shapeHelper.Parts_MyWidget(/*...*/);
// Hook up an event handler such that after rendering the (potentially expensive)
// shape template, we capture the output to the cached output object.
((ShapeMetadata) shape.Metadata).OnDisplayed(displayed => cachedOutput.Output = displayed.ChildContent);
} else {
// Found cached output, so simply output it instead of building
// the shape normally.
// This is a dummy shape, the name doesn't matter.
shape = shapeHelper.CachedShape();
// Hook up an event handler to fill the output of this shape with the cached output.
((ShapeMetadata)shape.Metadata).OnDisplaying(displaying => displaying.ChildContent = cachedOutput.Output);
// Replacing the ChildContent of the displaying context will cause the display manager
// to simply use that HTML output and skip template rendering.
}
return shape;
});
}
}
}
编辑:请注意,这只缓存从您的形状输出生成的 HTML。您在形状模板中执行的 Script.Require()、Capture() 和其他副作用等内容不会被播放。这实际上让我很生气,因为我试图缓存一个需要自己的样式表的模板,但样式表只会在第一次被引入。
Orchard 提供了一个名为 CacheManager 的服务,它很棒而且很酷,并且让缓存变得超级简单。文档中提到了它,但它并不是对如何使用它的特别有用的描述(http://docs.orchardproject.net/Documentation/Caching)。查看示例的最佳位置是 Orchard 核心代码和第三方模块,例如 Favicon 和 twitter 小部件(所有人都希望)。
幸运的是,其他好心人已经努力为你搜索 orchards 代码并写了一些关于它的漂亮的小博客文章。LatestTwitter 小部件的开发人员写了一篇简洁的帖子:http ://blog.maartenballiauw.be/post/2011/01/21/Writing-an-Orchard-widget-LatestTwitter.aspx 。NogginBox 的 Richard 也是如此:http ://www.nogginbox.co.uk/blog/orchard-caching-by-time 。当然,Bertrand 也有关于这个主题的有用帖子:http ://weblogs.asp.net/bleroy/archive/2011/02/16/caching-items-in-orchard.aspx