2

カスタムキャッシュをオンにしたいコントローラーアクションがいくつかあります。たとえば、コントローラー action があるとしますActionResult Index(string name) {}URL に " live=true " クエリ文字列パラメーターがない限り、このアクションの HTML をサーバーにキャッシュしたいと考えています。そのパラメータが存在する場合、そのアクション結果をサーバー キャッシュから削除し、通常どおり応答を返したいと思います。

通常、属性を使用OutputCache(Location=OutputCacheLocation.Server)してキャッシングを行います。live=trueパラメータが URL に存在する場合、この属性を拡張してキャッシュをクリアすることは可能ですか?

必要な動作を得るために OutputCache 属性をカスタマイズできない場合、これを達成するために使用できる代替手段はありますか?

アップデート

ジェームズのフィードバックに基づいて、私が持っているコードは次のとおりです。

public class LiveOutputCacheAttribute : OutputCacheAttribute
{
    private const string _resetParam = "live";
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var context = filterContext.HttpContext;
        AddLiveToVaryByParam();
        if (context.Request[_resetParam] == "true")
        {
            var urlToRemove = GetUrlToRemove(filterContext);
            context.Response.RemoveOutputCacheItem(urlToRemove);
            return;
        }
        base.OnActionExecuting(filterContext);
    }

    private void AddLiveToVaryByParam()
    {
        // add live reset flag when vary by param is specified
        if (VaryByParam != "*" && !VaryByParam.Contains("live"))
            VaryByParam = string.Format("{0};{1}",VaryByParam, _resetParam).TrimStart(';');
    }

    private static string GetUrlToRemove(ActionExecutingContext filterContext)
    {
        var routeValues = new RouteValueDictionary(filterContext.ActionParameters);
        var urlHelper = new UrlHelper(filterContext.RequestContext);
        string action = filterContext.ActionDescriptor.ActionName;
        string controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
        return urlHelper.Action(action, controller, routeValues);
    }
}

アクションでこれを使用する方法は次のとおりです。

[LiveOutputCache(Location = OutputCacheLocation.Server, Duration = 60 * 60, VaryByParam = "name")]
public ActionResult Index(string name)
{
    ViewData.Model = name + "-----" +  DateTime.Now.Ticks.ToString();
    return View();
}

問題は、live=true パラメーターを使用しても、元の要求がキャッシュから削除されないことです。ここで何か間違ったことをしていますか?

4

3 に答える 3

3

VaryByParam属性を使用して、ライブ オプションが true かどうかを確認できます。

public class LiveOutputCacheAttribute : OutputCacheAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (VaryByParam == "true")
        {
            // clear cache
            return;   
        }

        base.OnActionExecuting(filterContext);
    }
}

...

[LiveOutputCache(Location=OutputCacheLocation.Server, VaryByParam="live")]
public ActionResult Index(string name) 
{
    ...
}

そのクリア部分については、コントローラーアクションメソッドの出力キャッシュをプログラムでクリアする方法を参照してください。

于 2012-08-23T13:44:58.143 に答える
0

OutputCacheAttributeをカスタマイズして動作を取得することはできませんが、これを実現するために独自のCustomCacheAttributeを作成することはできます。これを行うには、OutputCacheAttributeのソースを取得し(MVCはオープンソースであるため、実行できます)、それをコピーして関数を書き換えますOnActionExecuting(ActionExecutingContext filterContext)

于 2012-08-23T12:54:34.477 に答える
0

ASP.NET MVC での独自のカスタム出力キャッシュの作成に関する私のブログ投稿を確認してくださいhttp://bstavroulakis.com/blog/web/custom-output-caching-in-asp-net-mvc/

満たされていない出力キャッシュからの次の期待がありました

1) 必要に応じてキャッシング オブジェクトを表示し、必要に応じてそのすべての子を無効にしてパーツを無効にすることができます。

2) 必要に応じてキャッシュを無効にする機能があります。

3) アイテムがキャッシュされる前後に何らかのロジックを用意します。

4) サイトの一部を動的にして、それらの部分のみをロードし、サイトの残りの部分を静的にする

5) サイトの他の部分でもキャッシュ構造を使用します。

私の行動:

  • キャッシュ内のオブジェクトを追加/削除/検索/... する独自の CacheManager を作成するには。
パブリック クラス CacheManager
    {
        #region ICacheManager メンバー

        public static void Add(string key, object value, int expireSeconds)
        {
            if (expireSeconds == CacheManagerKey.CacheLifeSpanForever)
                WebCache.Add(キー、値、null、System.Web.Caching.Cache.NoAbsoluteExpiration、System.Web.Caching.Cache.NoSlidingExpiration、CacheItemPriority.Normal、null);
            そうしないと
                WebCache.Add(キー、値、null、DateTime.MaxValue、TimeSpan.FromSeconds(expireSeconds)、CacheItemPriority.Normal、null);
        }

        public static bool Contains(文字列キー)
        {
            return WebCache.Get(キー) != null;
        }

        public static int Count()
        {
            WebCache.Count を返します。
        }

        public static void Insert(文字列キー、オブジェクト値)
        {
            WebCache.Insert(キー、値);
        }

        public static T Get (文字列キー)
        {
            return (T)WebCache.Get(キー);
        }

        public static List GetCacheKeys()
        {
            リストキー = new List();
            foreach (HttpContext.Current.Cache の DictionaryEntry エントリ) keys.Add(entry.Key.ToString());
            キーを返します。
        }

        public static void Remove(文字列キー)
        {
            WebCache.Remove(キー);
        }

        public static void RemoveAll()
        {
            リスト キー = GetCacheKeys();
            foreach (キーの文字列キー)
                WebCache.Remove(キー);
        }

        公開オブジェクト this[文字列キー]
        {
            得る
            {
                return WebCache[キー];
            }
            設定
            {
                WebCache[キー] = 値;
            }
        }

        #endregion

        public static System.Web.Caching.Cache WebCache
        {
            得る
            {
                System.Web.Caching.Cache キャッシュ = null;
                if (HttpContext.Current != null)
                    キャッシュ = HttpContext.Current.Cache;

                もし (キャッシュ == null)
                    キャッシュ = HttpRuntime.Cache;

                キャッシュを返します。
            }
        }
    }
    
  • その後、独自の属性を作成しました
        [AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
        パブリック クラス WebCacheAttribute : ActionFilterAttribute
        {
            public int 期間 { get; 設定; }
            公開文字列 CacheKey { get; 設定; }
            public Dictionary CacheParams {get; 設定; }
            public Type CacheReturnType { get; 設定; }
            パブリック文字列 ContentType { get; 設定; }
            public HeaderContentTypeEnum ResponseHeaderContentType{get;set;}
            公開文字列 CacheObj { get; 設定; }
            プライベート読み取り専用 ICacheHoleFiller _cacheHoleFiller;

            public WebCacheAttribute(int 期間、文字列 cacheKey、文字列 cacheParamsStr、HeaderContentTypeEnum 応答 = HeaderContentTypeEnum.Html、タイプ タイプ = null)
            {

            }

            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {

            }

            public T GetCachedParam(辞書パラメーター、bool isAjaxRequest)
            {

            }

            公開文字列 GetUniqueKey(bool isAjaxRequest)
            {

            }

            public void OnException(ExceptionContext filterContext)
            {

            }

            プライベート HtmlTextWriter tw;
            プライベート StringWriter sw;
            プライベート StringBuilder sb;
            プライベート HttpWriter 出力。

            public override void OnResultExecuting(ResultExecutingContext filterContext)
            {

            }

            public override void OnResultExecuted(ResultExecutedContext filterContext)
            {

            }
    }
    
var articleStr = CacheHelper.InvokeCacheMethod(typeof(HtmlHelperExtensions), "RenderArticlesCallback", new object[] { (int)articleType });
[WebCacheAttribute(CacheManagerKey.CacheLifeSpanForever, CacheManagerKey.Page_Article_Key, "articleTypeID")]
            public static string RenderArticlesCallback(int articleTypeID)
            {
public static class CacheHelper
    {
        パブリック デリゲート オブジェクト SourceDataDelegate(object[] args);

        public static T InvokeCacheMethod(Type type, string methodName, object[] args)
        {
            return (T)InvokeCacheMethod(type, methodName, null, args);
        }

        public static T InvokeCacheMethod(Type type, string methodName, object instance, object[] args)
        {
            var メソッド = type.GetMethod(メソッド名);
            var webCache = method.ReturnParameter.Member.GetCustomAttributes(typeof(WebCacheAttribute), true).FirstOrDefault();
            ディクショナリ cacheParameters = FixCacheParameters(メソッド、引数);
            T cachedObj;

            if (Config.CacheEnabled && webCache != null)
            {
                cachedObj = ((WebCacheAttribute)webCache).GetCachedParam(cacheParameters, false);
                if (cachedObj != null)
                    cachedObj を返します。
            }
            T returnObj = (T)method.Invoke(instance, args);
            SaveCachedData(webCache, returnObj);
            returnObj を返します。
        }

        public static void SaveCachedData(オブジェクト webCache、オブジェクト returnObj)
        {
            if (Config.CacheEnabled && webCache != null)
            {
                var fullParamString = ((WebCacheAttribute)webCache).GetUniqueKey(false);
                CacheManager.Add(fullParamString, returnObj, ((WebCacheAttribute)webCache).Duration);
            }
        }

        public static Dictionary FixCacheParameters(MethodInfo method, object[] args)
        {
            Dictionary cacheParameters = new Dictionary();
            if (args != null)
            {
                var 引数 = args.ToList();
                変数カウント = 0;
                var argsCount = args.Length;
                var methodParameters = method.GetParameters().ToList();

                foreach (args の var 引数)
                {
                    var key = methodParameters[カウント].Name;
                    オブジェクト値 = null;

                    if (argsCount > カウント)
                        値 = args[カウント];

                    if (値 != null && value.GetType() == typeof(string))
                        値 = (オブジェクト)value.ToString();

                    if (値 != null)
                        cacheParameters.Add(キー、値);

                    カウント++;
                }
            }

            cacheParameters を返します。
        }
    }

このすべての詳細については、私のブログ投稿をご覧ください => ASP.NET MVC でのカスタム出力キャッシュ

于 2013-09-17T08:35:06.810 に答える