Windows AzureMicrosoft.Web.DistributedCache.DistributedCacheOutputCacheProvider
を MVC3 アプリの outputCache プロバイダーとして使用する。関連するアクション メソッドは次のとおりです。
[ActionName("sample-cached-page")]
[OutputCache(Duration = 300, VaryByCustom = "User",
Location = OutputCacheLocation.Server)]
[Authorize(Users = "me@mydomain.tld,another@otherdomain.tld")]
public virtual ActionResult SampleCachedPage()
{
return View();
}
このビューを Web ブラウザーからロードすると、次の例外が発生します。
System.Configuration.Provider.ProviderException: When using a custom output cache provider like 'DistributedCache', only the following expiration policies and cache features are supported: file dependencies, absolute expirations, static validation callbacks and static substitution callbacks.
System.Configuration.Provider.ProviderException: When using a custom output cache provider like 'DistributedCache', only the following expiration policies and cache features are supported: file dependencies, absolute expirations, static validation callbacks and static substitution callbacks.
at System.Web.Caching.OutputCache.InsertResponse(String cachedVaryKey, CachedVary cachedVary, String rawResponseKey, CachedRawResponse rawResponse, CacheDependency dependencies, DateTime absExp, TimeSpan slidingExp)
at System.Web.Caching.OutputCacheModule.OnLeave(Object source, EventArgs eventArgs)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
[Authorize] 属性を削除すると、期待どおりにビューがキャッシュされます。これは、[Authorize] が必要なアクション メソッドに [OutputCache] を配置できないということですか? または、キャッシュの静的検証コールバック メソッドを使用するカスタム実装で AuthorizeAttribute をオーバーライドする必要がありますか?
更新 1
Evan の回答の後、IIS Express (Azure の外部) で上記のアクション メソッドをテストしました。OutputCache 属性の VaryByCustom = "User" プロパティのオーバーライドは次のとおりです。
public override string GetVaryByCustomString(HttpContext context, string custom)
{
return "User".Equals(custom, StringComparison.OrdinalIgnoreCase)
? Thread.CurrentPrincipal.Identity.Name
: base.GetVaryByCustomString(context, custom);
}
サンプルのキャッシュ ページに me@mydomain.tld としてアクセスすると、ページの出力がキャッシュされ、ビューに「このページは 2011 年 12 月 31 日 11:06: 12 AM (UTC) にキャッシュされました」と表示されます。その後、サインアウトして another@otherdomain.tld としてサインインし、ページにアクセスすると、「このページは 2011 年 12 月 31 日 11:06: 38 AM (UTC) にキャッシュされました」と表示されます。me@mydomain.tld として再度サインインしてページに再度アクセスすると、キャッシュに「このページは 2011 年 12 月 31 日 11:06: 12 AM (UTC) にキャッシュされました」と再度表示されます。さらにサインイン/サインアウトを試みると、ユーザーに応じて異なる出力がキャッシュされて返されることが示されます。
これにより、出力がユーザーに基づいて個別にキャッシュされていると思われます。これは、VaryByCustom = "User" 設定とオーバーライドの意図です。問題は、Azure の分散キャッシュ プロバイダーでは機能しないことです。Evan さん、公開コンテンツのキャッシュのみが残っていることについてお答えいただけますか?
更新 2
ソースを掘り下げたところ、既製の AuthorizeAttribute には実際には非静的検証コールバックがあることがわかりました。からの抜粋は次のOnAuthorization
とおりです。
if (AuthorizeCore(filterContext.HttpContext)) {
// ** IMPORTANT **
// Since we're performing authorization at the action level, the authorization code runs
// after the output caching module. In the worst case this could allow an authorized user
// to cause the page to be cached, then an unauthorized user would later be served the
// cached page. We work around this by telling proxies not to cache the sensitive page,
// then we hook our custom authorization code into the caching mechanism so that we have
// the final say on whether a page should be served from the cache.
HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
cachePolicy.SetProxyMaxAge(new TimeSpan(0));
cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
}
else {
HandleUnauthorizedRequest(filterContext);
}
CacheValidationHandler
もちろんprotected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase)
、これは静的ではありません。静的ではない理由の 1 つは、上記の IMPORTANT コメントで述べたように、 を呼び出すためprotected virtual bool AuthorizeCore(HttpContextBase)
です。
静的キャッシュ検証コールバック メソッドから AuthorizeCore ロジックを実行するには、AuthorizeAttribute インスタンスの Users プロパティと Roles プロパティを知る必要があります。ただし、プラグインする簡単な方法はないようです。OnAuthorization をオーバーライドして、これら 2 つの値を HttpContext (Items コレクション?) に入れ、OnCacheAuthorization をオーバーライドしてそれらを元に戻す必要があります。しかし、それは汚いにおいがします。
OutputCache 属性で VaryByCustom = "User" プロパティを慎重に使用する場合、OnCacheAuthorization をオーバーライドして、常に HttpValidationStatus.Valid を返すことはできますか? アクション メソッドに OutputCache 属性がない場合、このコールバックが呼び出されることを心配する必要はありませんよね? また、VaryByCustom = "User" のない OutputCache 属性がある場合、どのユーザー要求がキャッシュされたコピーを作成したかに関係なく、ページがキャッシュされたバージョンを返す可能性があることは明らかです。これはどれほど危険ですか?