属性を使用して特定のアクションのASP.NET MVCでキャッシュを防止する


196

ASP.NET MVC 3アプリケーションがあります。このアプリケーションは、jQueryを介してレコードを要求します。jQueryは、結果をJSON形式で返すコントローラーアクションを呼び出します。これを証明することはできませんでしたが、データがキャッシュされるのではないかと心配しています。

すべてのアクションではなく、特定のアクションにのみキャッシュを適用したい。

データがキャッシュされないようにするためにアクションに設定できる属性はありますか?そうでない場合、ブラウザがキャッシュされたセットの代わりに毎回新しいレコードのセットを確実に取得するにはどうすればよいですか?


1
あなたは何かがキャッシュされていることを推測されている場合、私はあなたがここでキャッシュ制御機構をよく読んですることをお勧めします。w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9

回答:


304

JQueryが結果をキャッシュしないようにするには、ajaxメソッドで次のように記述します。

$.ajax({
    cache: false
    //rest of your ajax setup
});

または、MVCでのキャッシングを防ぐために、独自の属性を作成しましたが、同じことができます。コードは次のとおりです。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NoCacheAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
        filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
        filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
        filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        filterContext.HttpContext.Response.Cache.SetNoStore();

        base.OnResultExecuting(filterContext);
    }
}

次に、コントローラをで装飾します[NoCache]。または、これをすべて行う場合は、ここにあるように、(もしあれば)コントローラーを継承する基本クラスのクラスに属性を置くだけです。

[NoCache]
public class ControllerBase : Controller, IControllerBase

コントローラ全体を装飾するのではなく、キャッシュ不可にする必要がある場合は、この属性を使用して一部のアクションを装飾することもできます。

NoCacheブラウザーでレンダリングしたときにクラスまたはアクションになかった場合、それが機能していることを確認したい場合は、変更をコンパイルした後、ブラウザーで「ハードリフレッシュ」(Ctrl + F5)を実行する必要があることに注意してください。そうするまで、ブラウザは古いキャッシュバージョンを保持し、「通常の更新」(F5)でそれを更新しません。


1
上記のソリューションですべてを試しましたが、うまくいきません。
Obi Wan

9
cache:falseは、クエリ文字列にjQueryを付加するだけで変化する値をブラウザに「だまして」、リクエストが他のものであると思わせるようにするのはcache:falseだけであることは私の理解です(私はjQueryの専門家ではありません)。理論的には、これはブラウザが結果を引き続きキャッシュし、キャッシュされた結果を使用しないことを意味します。応答ヘッダーを介したキャッシュを無効にするには、クライアントでより効率的である必要があります。
Josh、

2
コントローラレベルでのみ機能し、アクションレベルでは機能しません。
Ramesh

3
私は公式のASP.NETパッケージにそのような属性を含めることを支持します:-)
USR-ローカルΕΨΗΕΛΩΝ

1
仕様のセクションである@Frédéricは、キャッシュがストアのないコンテンツをキャッシュできないことを示しています。「no-store」応答ディレクティブは、キャッシュが即時の要求または応答のいずれの部分も格納してはならないことを示します。
kristianp 2016年

258

組み込みのcache属性を使用して、キャッシュを防止できます。

.net Frameworkの場合: [OutputCache(NoStore = true, Duration = 0)]

.net Coreの場合: [ResponseCache(NoStore = true, Duration = 0)]

ブラウザに強制的にキャッシュを無効にすることは不可能であることに注意してください。あなたができる最善のことは、ほとんどのブラウザーが尊重する提案を、通常はヘッダーまたはメタタグの形式で提供することです。このデコレーター属性はサーバーのキャッシュを無効にし、次のヘッダーも追加します:Cache-Control: public, no-store, max-age=0。メタタグは追加されません。必要に応じて、ビューに手動で追加できます。

さらに、JQueryや他のクライアントフレームワークは、タイムスタンプやGUIDなどの要素をURLに追加することで、ブラウザをだましてリソースのキャッシュバージョンを使用させないようにします。これはブラウザにリソースを再度要求させるのに効果的ですが、実際にはキャッシュを妨げません。

最後に。サーバーとクライアントの間でリソースをキャッシュすることもできます。ISP、プロキシ、およびその他のネットワークデバイスもリソースをキャッシュし、実際のリソースを確認せずに内部ルールを使用することがよくあります。これらについてできることはあまりありません。良いニュースは、通常、秒や分などの短い時間枠でキャッシュすることです。


3
これは問題を完全には扱っていないと思います。これにより、ASP.NETキャッシュは無効になりますが、ブラウザキャッシュは無効になりません。
Rosdi Kasim

22
ブラウザに強制的にキャッシュを無効にすることはできません。あなたができる最善のことは、ほとんどのブラウザーが尊重する提案を、通常はヘッダーまたはメタタグの形式で提供することです。このデコレーター属性は、.NETサーバーのキャッシュを無効にし、ヘッダーも追加しCache-Control:public, no-store, max-age=0ます。メタタグは追加されません。必要に応じて、ビューに手動で追加できます。
Jaguir 2014年

1
あなたが使用する理由NoStore = trueDuration = 0(私が成功して使用したおかげで)理由は理解できますがVaryByParam = "None"、他の2つのオプションがパラメーターに関係なくすべてのリクエストに影響するため、どのような追加の効果がありますか?
コーディング終了(

MVCでは必須ではないと思います。明示的にしているだけです。ASP.NET Webフォームとユーザーコントロールでは、この属性またはVaryByControl属性が必要であることを覚えています。
Jaguir 2015

1
ASP.NET Coreの場合: '[ResponseCache(NoStore = true、Duration = 0)]'
Jeff

48

あなたに必要なのは:

[OutputCache(Duration=0)]
public JsonResult MyAction(

または、コントローラ全体で無効にしたい場合:

[OutputCache(Duration=0)]
public class MyController

ここでのコメントでの議論にもかかわらず、これはブラウザーのキャッシュを無効にするのに十分です-これにより、ASP.Netはブラウザーにドキュメントがすぐに期限切れになることを通知する応答ヘッダーを発行します。

OutputCache Duration = 0応答ヘッダー:max-age = 0、s-maxage = 0


6
コントローラアクションでDuration = 0のみを使用して戻るボタンがクリックされた場合、IE8は引き続きキャッシュされたバージョンのページをレンダリングします。NoStore = trueをDuration = 0とともに使用すると(Jaredの回答を参照)、私の場合の動作が修正されました。
Keith Ketterer、2015年

3
これは、設定のやや好奇心振る舞いがあるCache-Controlpublic
ta.speot.is

max-age=0「キャッシュを無効にする」という意味ではありません。これは、応答コンテンツがすぐに古くなっていると見なされることを意味するだけですが、キャッシュはそれをキャッシュすることが許可されています。ブラウザは、キャッシュされた古いコンテンツの鮮度を使用前に検証する必要がありますが、追加のディレクティブmust-revalidateが指定されていない限り、必須ではありません。
フレデリック

14

コントローラーアクションで、ヘッダーに次の行を追加します

    public ActionResult Create(string PositionID)
    {
        Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
        Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
        Response.AppendHeader("Expires", "0"); // Proxies.

5

以下NoCacheは、mattytommoによって提案された属性であり、Chris Moschiniの回答からの情報を使用して簡略化されています。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NoCacheAttribute : OutputCacheAttribute
{
    public NoCacheAttribute()
    {
        this.Duration = 0;
    }
}

何らかの理由で、MVC 3では継続時間を0に設定できるだけではありません。これらの注釈を追加する必要があります...回避策をありがとう!
micahhoover 2015年

max-age=0「キャッシュを無効にする」という意味ではありません。これは、応答コンテンツがすぐに古くなっていると見なされることを意味するだけですが、キャッシュはそれをキャッシュすることが許可されています。ブラウザーは、キャッシュされた古いコンテンツの鮮度を使用前に検証する必要がありますが、追加のディレクティブmust-revalidateが指定されていない限り、必須ではありません。
フレデリック

完全を期すために、最小限で適切なディレクティブはですno-cache。これにより、キャッシュは引き続き許可されますが、使用前にオリジンサーバーで再検証することが義務付けられます。再検証されたキャッシュを回避するために、no-storeとともに追加する必要がありますno-cache。(no-store揮発性キャッシュがとしてマークされno-storeたコンテンツをキャッシュすることが許可されているため、それだけでは明らかに間違っています。)
FrédéricNov

4

MVC6(DNX)の場合、System.Web.OutputCacheAttribute

注:NoStore期間パラメーターを設定する場合は考慮されません。最初の登録の初期期間を設定し、これをカスタム属性で上書きすることが可能です。

しかし、 Microsoft.AspNet.Mvc.Filters.ResponseCacheFilter

 public void ConfigureServices(IServiceCollection services)
        ...
        services.AddMvc(config=>
        {
            config.Filters.Add(
                 new ResponseCacheFilter(
                    new CacheProfile() { 
                      NoStore=true
                     }));
        }
        ...
       )

カスタム属性で初期フィルターを上書きすることが可能です

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public sealed class NoCacheAttribute : ActionFilterAttribute
    {
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            var filter=filterContext.Filters.Where(t => t.GetType() == typeof(ResponseCacheFilter)).FirstOrDefault();
            if (filter != null)
            {
                ResponseCacheFilter f = (ResponseCacheFilter)filter;
                f.NoStore = true;
                //f.Duration = 0;
            }

            base.OnResultExecuting(filterContext);
        }
    }

ここにユースケースがあります

    [NoCache]
    [HttpGet]
    public JsonResult Get()
    {            
        return Json(new DateTime());
    }

1

MVCでの出力キャッシュ

[OutputCache(NoStore = true、Duration = 0、Location = "None"、VaryByParam = "*")]

または
[OutputCache(NoStore = true、Duration = 0、VaryByParam = "None")]


他のコメント(参照123を多数の答えはすでにこれを使用して示唆に)。2行目が間違っているため、一部のブラウザーで問題が発生します。
フレデリック


0

ASP.NET MVC 5ソリューション:

  1. 中央の場所での防止コードのキャッシュ:App_Start/FilterConfig.csRegisterGlobalFilters方法:
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            // ...
            filters.Add(new OutputCacheAttribute
            {
                NoStore = true,
                Duration = 0,
                VaryByParam = "*",
                Location = System.Web.UI.OutputCacheLocation.None
            });
        }
    }
  1. それが整ったら、別のOutputCacheディレクティブを、ControllerまたはViewレベルで適用することにより、グローバルフィルターをオーバーライドできることを理解しています。通常のコントローラーの場合
[OutputCache(NoStore = true, Duration = 0, Location=System.Web.UI.ResponseCacheLocation.None, VaryByParam = "*")]

またはApiControllerそれがそうなら

[System.Web.Mvc.OutputCache(NoStore = true, Duration = 0, Location = System.Web.UI.OutputCacheLocation.None, VaryByParam = "*")]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.