我已将输出缓存添加到我的应用中的几个操作,以便轻松提升性能。但是,这些操作还需要在每个请求之后递增一个计数器(它是一个视图计数器),方法是点击一个Redis数据库。
首先,我想我可以调整动作过滤器执行的顺序,以确保计算视图:
public class CountersAttribute : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
//increment my counter all clever like
base.OnResultExecuted(filterContext);
}
}
但那不起作用;显然,OutputCacheAttribute的行为与普通的动作过滤器不同。然后我尝试实现自定义输出缓存:
public class OutputCacheWithCountersAttribute : OutputCacheAttribute
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
//straight to the source to get my headcount!
base.OnResultExecuted(filterContext);
}
}
不,也没有工作;缓存操作后,操作过滤器似乎完全被忽略。长号。
那么,呃,有没有办法(没有实现自定义输出缓存提供程序),以确保我的观点被正确计算,这是干净和明智的?
答案 0 :(得分:14)
OutputCacheAttribute
方式有局限性,Paul Hiles开发的名为DonutOutputCache的自定义属性有助于克服这些限制。
它支持的一个重要功能是你可以拥有一个动作过滤器,即使动作被标记为cache属性,也可以一直调用它。
对于前。您希望在5秒内缓存一个操作,同时您希望每次操作都使用LogThis
过滤器接收请求时进行记录,您可以通过以下方式实现该操作,
[LogThis]
[DonutOutputCache(Duration=5, Order=100)]
public ActionResult Index()
来自Paul,
是的,与内置的OutputCacheAttribute不同,动作过滤器会 即使从缓存中检索页面也会执行。唯一的警告 添加是你需要注意过滤顺序。如果 您的操作过滤器实现OnResultExecuting或OnResultExecuted 然后这些方法将在所有情况下执行,但是 OnActionExecuting和OnActionExecuted,只有在执行时才会执行 过滤器在DonutOutputCacheAttribute之前运行。这是因为 MVC阻止后续过滤器执行的方式 设置filterContext.Result属性,这是我们需要做的 输出缓存。
我认为您不能依赖于操作过滤器的顺序 在动作或控制器上定义。确保一个过滤器运行 在另一个之前,您可以使用存在的Order属性 在所有ActionFilterAttribute实现上。没有的任何行动 order属性集,默认值为-1,表示它们将 在具有显式Order值的过滤器之前执行。
因此,在您的情况下,您只需将Order = 100添加到 DonutOutputCache属性和所有其他过滤器将在之前执行 缓存过滤器。
答案 1 :(得分:1)
即使页面已缓存,您也可以从布局视图进行AJAX调用并跟踪访问者。这就是Google Analytics所做的事情。我建议从布局视图中执行此操作,因为它将在使用该布局的所有视图中执行。 还有一个评论,假设您有两个布局视图:一个用于站点的公共部分,另一个用于后端(仅限员工)。您可能对跟踪用户而不是员工感兴趣,因此这是在布局视图中跟踪的另一个好处。如果将来您想要跟踪员工正在做什么,您可以为后端布局视图添加不同的跟踪器。 我希望它有所帮助。
答案 2 :(得分:0)
原因实际上是在.NET源代码中,与DonutOutputCache无关:
public void SetCacheability(HttpCacheability cacheability)
{
if (cacheability < HttpCacheability.NoCache || HttpCacheability.ServerAndPrivate < cacheability)
throw new ArgumentOutOfRangeException("cacheability");
if (HttpCachePolicy.s_cacheabilityValues[(int) cacheability] >= HttpCachePolicy.s_cacheabilityValues[(int) this._cacheability])
return;
this.Dirtied();
this._cacheability = cacheability;
}
换句话说,如果您先设置NoCache(值为1),如果您尝试设置更高的值(例如4(公共)),它将始终返回。
唯一的解决方案是分叉项目并将其扩展到您需要的方式,或者发送一个拉取请求来标记protected ICacheHeadersHelper CacheHeadersHelper
中的DonutOutputCacheAttribute
答案 3 :(得分:0)
使用始终执行的“验证回调”,即使应该为缓存的页面提供服务
typedef struct xyz{
int x, y, z;
} xyz_t;
xyz_t array[] = {
{.x = 14, .y = 16, .z = 18},
{.x = 34, .y = 36, .z = 38},
{.x = 64, .y = 66, .z = 68},
};
typedef struct {
xyz_t *pointer;
} blue_t;
int main()
{
blue_t red;
red.pointer = &array;
printf("%d",red.pointer[1].z);
}
注意:public class MyCacheAttribute : OutputCacheAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
SaveToLog();
httpContext.Response.Cache.AddValidationCallback(MyCallback, null);
base.OnResultExecuting(filterContext);
}
// This method is called each time when cached page is going to be served
private void MyCallback(HttpContext context, object data, ref HttpValidationStatus validationStatus)
{
SaveToLog();
}
}
在两个地方被调用,这是设计使然(在绕过缓存时第一次调用,在提供缓存版本时秒调用)