كيفية تشغيل الإخراج للتخزين المؤقت للمستخدمين المصادقين في ASP.NET MVC؟

StackOverflow https://stackoverflow.com/questions/2109928

  •  22-09-2019
  •  | 
  •  

سؤال

لدي تطبيق ASP.NET MVC. أنا بحاجة إلى تخزين بعض الصفحات ولكن فقط للمستخدمين غير المصابين.

لقد حاولت استخدام VaryByCustom="user" كالآتي GetVaryByCustomString التنفيذ:

public override string GetVaryByCustomString(HttpContext context, string custom)
{
  if (custom == "user")
  {
      if (context.User.Identity.IsAuthenticated)
      {
        return context.User.Identity.Name;
      }
      else
      {
        return "";
      }
  }  

  return base.GetVaryByCustomString(context, custom);
}

ومع ذلك ، هذا ليس بالضبط ما أحتاجه لأن الصفحات لا تزال مخزنة مؤقتًا. الفرق الوحيد هو أنه تم تخزينه مؤقتًا الآن لكل مستخدم بشكل منفصل.

أحد الحلول الممكنة هو العودة Guid.NewGuid() في كل مرة يتم فيها مصادقة المستخدم ، ولكن يبدو لي مضيعة كبيرة للموارد بالنسبة لي.

هل لديك أي نصائح لي؟

هل كانت مفيدة؟

المحلول

إذن هذا ما فعلته:

public class NonAuthenticatedOnlyCacheAttribute : OutputCacheAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
      var httpContext = filterContext.HttpContext;

      if (httpContext.User.Identity.IsAuthenticated)
      {
        // it's crucial not to cache Authenticated content
        Location = OutputCacheLocation.None;
      }

      // this smells a little but it works
      httpContext.Response.Cache.AddValidationCallback(IgnoreAuthenticated, null);

      base.OnResultExecuting(filterContext);
    }

    // This method is called each time when cached page is going to be
    // served and ensures that cache is ignored for authenticated users.
    private void IgnoreAuthenticated(HttpContext context, object data, ref HttpValidationStatus validationStatus)
    {
      if (context.User.Identity.IsAuthenticated)            
        validationStatus = HttpValidationStatus.IgnoreThisRequest;          
      else          
        validationStatus = HttpValidationStatus.Valid;          
    }
}

شكرا جزيلا ل كريج ستونتز الذي أشارني إلى تصحيح الاتجاه والذي أجابني عن غير قصد.

نصائح أخرى

يتم التخزين المؤقت للسمات بشكل عام ، ثم تحتاج إلى تخزين الموقع الأصلي. إذا قمت بالوصول إلى الصفحة التي تم تسجيلها ، فستضع موقعًا على أي شيء ، ثم عند الوصول إلى مجهول ، لا يزال هناك شيء.

public class AuthenticatedOnServerCacheAttribute : OutputCacheAttribute
{
    private OutputCacheLocation? originalLocation;

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        var httpContext = filterContext.HttpContext;

        if (httpContext.User.Identity.IsAuthenticated)
        {
            originalLocation = originalLocation ?? Location;
            Location = OutputCacheLocation.None;
        }
        else
        {
            Location = originalLocation ?? Location;
        }

        base.OnResultExecuting(filterContext);
    }
}

الإجابة المقبولة صحيحة لكنها لا تعمل على التخزين المؤقت بهذه الطريقة وجهات النظر الجزئية. لقد جمعت كلا الاختلافين:GetVaryByCustomString وحدد Duration إلى الحد الأدنى - للآراء الجزئية و AddValidationCallback طريقة للصفحات. في الواقع ، من الممكن استخدام الطريقة الأولى فقط ولكن الطريقة الثانية لا تبدو باهظة الثمن - إنها لا تتصل OnResultExecuting في كل مرة ولكن معالج مسجل فقط.

لذلك فئة سمة ذاكرة التخزين المؤقت المخصصة

public class CacheAttribute : OutputCacheAttribute
{   

    public CacheAttribute()
    {
      Duration = 300;  /*default cache time*/
    }

    private bool _partialView;

    /// <summary>
    /// Set true if Partial view is cached
    /// </summary>
    public bool PartialView
    {
      get { return _partialView; }
      set
      {
        _partialView = value;
        if ( _partialView ) {
          VaryByCustom = "Auth";
        }
      }
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        if ( PartialView ) OnCachePartialEnabled( filterContext );
        else OnCacheEnabled(filterContext);

        base.OnResultExecuting( filterContext );     
    }

    private OutputCacheLocation? originalLocation;
    private int? _prevDuration;
    protected void OnCachePartialEnabled(ResultExecutingContext filterContext)
    {
      var httpContext = filterContext.HttpContext;

      if ( !_prevDuration.HasValue) _prevDuration = Duration;
      Duration = httpContext.User.Identity.IsAuthenticated ? 1 : _prevDuration.Value;
    }

    protected void OnCacheEnabled(ResultExecutingContext filterContext)
    {
      var httpContext = filterContext.HttpContext;

      if ( httpContext.User.Identity.IsAuthenticated ) {
        // it's crucial not to cache Authenticated content
        originalLocation = originalLocation ?? Location;
        Location = OutputCacheLocation.None;
      }
      else {
      Location = originalLocation ?? Location;
    }

      // this smells a little but it works
      httpContext.Response.Cache.AddValidationCallback( IgnoreAuthenticated, null );      
    }

    // This method is called each time when cached page is going to be
    // served and ensures that cache is ignored for authenticated users.
    private void IgnoreAuthenticated(HttpContext context, object data, ref HttpValidationStatus validationStatus)
    {
      validationStatus = context.User.Identity.IsAuthenticated 
        ? HttpValidationStatus.IgnoreThisRequest 
        : HttpValidationStatus.Valid;
    }
}

تجاوز طريقة getVaryByCustomString في global.asax.cs

public override string GetVaryByCustomString(HttpContext context, string custom)
{ 
    if ( custom == "Auth" ) {
      //do not cache when user is authenticated
      if ( context.User.Identity.IsAuthenticated ) {
        return base.GetVaryByCustomString( context, custom );
      }
      return "NotAuth";
    }     
    return base.GetVaryByCustomString( context, custom );
}

استخدمه مثل هذا:

[Cache]
public virtual ActionResult Index()
{
    return PartialView();
}

[ChildActionOnly, Cache(PartialView=true)]
public virtual ActionResult IndexPartial()
{
    return PartialView();
}

محدث: لقد أضفت أيضًا إصلاح Fujiy هنا

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top