簡體   English   中英

.net mvc:自定義authorizeattribute和customoutputcache提供程序

[英].net mvc: custom authorizeattribute and customoutputcache provider

我寫了一個自定義的outputcache提供程序,將輸出保存在磁盤上,除了使用AuthorizeAttribute裝飾的動作外,它可以正常工作。
考慮到問題,該解決方案似乎具有自定義的AuthorizeAttribute來管理緩存。
然后,我添加了自定義的AuthorizeAttribute,但是不幸的是,我遇到了錯誤
當使用像'FileCacheProvider'這樣的自定義輸出緩存提供程序時,僅支持以下到期策略和緩存功能:文件依賴項,絕對到期,靜態驗證回調和靜態替換回調。

編碼:

自定義OutputCache提供程序(FileCacheProvider)

public class FileCacheProvider : OutputCacheProvider
{

    public string CacheLocation
    {
        get
        {
            if (ConfigurationManager.AppSettings["FileCacheLocationRelativePath"] == null)
            {
                throw new ApplicationException("The FileCacheLocationRelativePath AppSettings key is not configured.");
            }
            string strCacheLocation = ConfigurationManager.AppSettings["FileCacheLocationRelativePath"];
            strCacheLocation = HttpContext.Current.Server.MapPath(strCacheLocation);
            return strCacheLocation + @"\";
        }
    }

    public override object Add(string key, object entry, DateTime utcExpiry)
    {
        object obj = this.Get(key);
        if (obj != null)
        {
            return obj;
        }
        else
        {
            this.Set(key, entry, utcExpiry);
            return entry;
        }
    }


    public override void Remove(string key)
    {
        string filePath = GetFullPathForKey(key);
        if (File.Exists(filePath))
        {
            File.Delete(filePath);
        }
    }


    public override object Get(string key)
    {
        string filePath = GetFullPathForKey(key);
        if (!File.Exists(filePath))
        {
            return null;
        }
        CacheItem item = null;
        FileStream fileStream = File.OpenRead(filePath);
        BinaryFormatter formatter = new BinaryFormatter();
        item = (CacheItem)formatter.Deserialize(fileStream);
        fileStream.Close();
        if (item == null || item.Expiry <= DateTime.UtcNow)
        {
            Remove(key);
            return null;
        }
        return item.Item;
    }


    public override void Set(string key, object entry, DateTime utcExpiry)
    {
        string filePath = GetFullPathForKey(key);
        CacheItem item = new CacheItem { Expiry = utcExpiry, Item = entry };
        FileStream fileStream = File.OpenWrite(filePath);
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(fileStream, item);
        fileStream.Close();
    }

    private string GetFullPathForKey(string key)
    {
        string temp = key.Replace('/', '$');
        return CacheLocation + temp;
    }
}


[Serializable]
public class CacheItem
{
    public object Item { get; set; }
    public DateTime Expiry { get; set; }
}

定制AuthorizeAttribute(DFAuthorizeAttribute)

[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class DFAuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{


    private AuthenticationManager authentication = new AuthenticationManager();


    protected void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
    {
        validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
    }

    protected void SetCachePolicy(AuthorizationContext filterContext)
    {
        HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
        cachePolicy.SetProxyMaxAge(new TimeSpan(0));
        cachePolicy.AddValidationCallback(CacheValidateHandler, null);
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        if (AuthorizeCore(filterContext.HttpContext))
        {
            SetCachePolicy(filterContext);
        }
        else if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            // auth failed, redirect to login page
            filterContext.Result = new HttpUnauthorizedResult();
        }
        else if (authentication != null || authentication.AuthenticationData != null)
        {
            SetCachePolicy(filterContext);
        }
        else
        {
            ViewDataDictionary viewData = new ViewDataDictionary();
            viewData.Add("Message", "You do not have sufficient privileges for this operation.");
            filterContext.Result = new ViewResult { ViewName = "Error", ViewData = viewData };
        }

    }


}

Web.config

<caching>
  <outputCache defaultProvider="FileCacheProvider">
    <providers>
      <add name="FileCacheProvider" type="MyNameSpace.FileCacheProvider"/>
    </providers>
  </outputCache>
  <outputCacheSettings>
    <outputCacheProfiles>
      <add name="Index" duration="3600" />
    </outputCacheProfiles>
  </outputCacheSettings>
</caching>

行動

[OutputCache(CacheProfile = "Index")]
[MyNameSpace.DFAuthorize]
public ActionResult Index(string pageId)
{
    ....
}

任何幫助將不勝感激

問題是由於您的CacheValidateHandler不是靜態方法。 我測試了它,如果您評論它的內容並將其更改為靜態,錯誤就會消失。

但是,當您這樣做時,它也不會達到方法的斷點,因此我認為這不是可行的解決方案。

在該線程上似乎對此進行了很多討論,但是似乎沒有真正的答案。

我相信自定義輸出緩存不是設計為與AuthorizeAttribute結合使用的,否則這是某種MVC錯誤。 請記住,MVC比OutputCache(.NET 2.0中的OutputCache)要新得多,因此,這可能只是不兼容,如果不引入重大的API更改就無法解決。 如果您覺得這很重要,可以向MVC小組報告。

但是,恕我直言,您應該只使用System.Runtime.Caching.ObjectCache抽象類,該抽象類也可以擴展為基於文件的,而不是輸出緩存來處理這種情況。 它實際上並不緩存頁面內容(您只是緩存數據塊),但是如果您要解決的話,它仍然可以防止數據庫往返。

請注意,您仍然可以將FileCacheProvider用於不在登錄名后面的公共頁面,但是需要AuthorizeAttribute的每個操作都應改用System.Runtime.Caching提供程序。 同樣,緩存登錄后的頁面也是一種不尋常的情況,因為它們往往在大多數時間都需要實時查看數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM