// Copyright 2004-2009 Castle Project - http://www.castleproject.org/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. namespace Castle.MonoRail.Framework { using System; using System.Web; /// /// Defines the cache configuration for an action. /// [AttributeUsage(AttributeTargets.Method|AttributeTargets.Class, AllowMultiple = false, Inherited = true), Serializable] public class CacheAttribute : Attribute, ICachePolicyConfigurer { private readonly HttpCacheability cacheability; private bool allowInHistory, slidingExpiration, validUntilExpires; private bool setEtagFromFileDependencies, setLastModifiedFromFileDependencies; private bool setNoServerCaching, setNoStore, setNoTransforms, omitVaryStar; private string cacheExtension; private string etag; private int duration; private string varyByCustom, varyByHeaders, varyByParams; private DateTime? lastModified; private TimeSpan? maxAge, proxyMaxAge; private HttpCacheRevalidation revalidation; #if DOTNET2SP1 || DOTNET35 private string varyByContentEncodings; #endif /// /// Initializes a new instance of the class. /// /// Sets the Cache-Control HTTP header. /// The Cache-Control HTTP header controls how documents are to be cached on the network. public CacheAttribute(HttpCacheability cacheability) { this.cacheability = cacheability; allowInHistory = true; validUntilExpires = true; revalidation = HttpCacheRevalidation.None; } /// /// From MSDN: Makes the response is available in the client browser /// History cache, regardless of the HttpCacheability setting /// made on the server, when the allow parameter is true. /// /// /// When HttpCacheability is set to NoCache or ServerAndNoCache the Expires /// HTTP header is by default set to -1; this tells the client not to /// cache responses in the History folder, so that when you use the back/forward buttons /// the client requests a new version of the response each time. You can override this /// behavior by calling the SetAllowResponseInBrowserHistory method with the /// allow parameter set to true. /// /// If HttpCacheability is set to values other than NoCache or ServerAndNoCache, calling the SetAllowResponseInBrowserHistory method with either value for allow has no effect. /// /// public bool AllowInHistory { get { return allowInHistory; } set { allowInHistory = value; } } /// /// If true, sets the ETag HTTP header based on the time stamps of the handler's file dependencies. /// public bool SetEtagFromFileDependencies { get { return setEtagFromFileDependencies; } set { setEtagFromFileDependencies = value; } } /// /// If true, sets the Last-Modified HTTP header based on the time stamps of the handler's file dependencies. /// public bool SetLastModifiedFromFileDependencies { get { return setLastModifiedFromFileDependencies; } set { setLastModifiedFromFileDependencies = value; } } /// /// If true, stops all origin-server caching for the current response. /// public bool SetNoServerCaching { get { return setNoServerCaching; } set { setNoServerCaching = value; } } /// /// If true, sets the Cache-Control: no-store HTTP header. /// public bool SetNoStore { get { return setNoStore; } set { setNoStore = value; } } /// /// If true, sets the Cache-Control: no-transform HTTP header. /// public bool SetNoTransforms { get { return setNoTransforms; } set { setNoTransforms = value; } } /// /// If true, includes the vary:* header in the response when varying by parameters. /// public bool OmitVaryStar { get { return omitVaryStar; } set { omitVaryStar = value; } } /// /// From MSDN: Sets cache expiration to from absolute to sliding. /// /// /// When cache expiration is set to sliding, the Cache-Control /// HTTP header will be renewed with each response. This expiration mode /// is identical to the IIS configuration option to add an expiration /// header to all output set relative to the current time. /// /// If you explicitly set sliding expiration to off (false), that setting /// will be preserved and any attempts to enable sliding expiration will /// silently fail. This method does not directly map to an HTTP header. /// It is used by subsequent modules or worker requests to set origin-server cache policy. /// /// public bool SlidingExpiration { get { return slidingExpiration; } set { slidingExpiration = value; } } /// /// Specifies whether the ASP.NET cache should ignore HTTP Cache-Control /// headers sent by the client that invalidate the cache. /// /// /// This method is provided because some browsers, when refreshing a /// page view, send HTTP cache invalidation headers to the Web server /// and evict the page from the cache. When the validUntilExpires parameter /// is true, ASP.NET ignores cache invalidation headers and the page /// remains in the cache until it expires. /// public bool ValidUntilExpires { get { return validUntilExpires; } set { validUntilExpires = value; } } /// /// Text to be appended to the Cache-Control HTTP header. /// public string CacheExtension { get { return cacheExtension; } set { cacheExtension = value; } } /// /// Sets the ETag HTTP header to the specified string. /// /// /// The ETag header is a unique identifier for a specific version of /// a document. It is used by clients to validate client-cached content to /// avoid requesting it again. Once an ETag header is set, subsequent /// attempts to set it fail and an exception is thrown. /// public string ETag { get { return etag; } set { etag = value; } } /// /// Cache Duration (in seconds) /// public int Duration { get { return duration; } set { duration = value; } } #if DOTNET2SP1 || DOTNET35 /// /// Gets or sets the list of all Content-Encoding headers that will be used to vary the output cache. /// public string VaryByContentEncodings { get { return varyByContentEncodings; } set { varyByContentEncodings = value; } } #endif /// /// Specifies a custom text string to vary cached output responses by. /// public string VaryByCustom { get { return varyByCustom; } set { varyByCustom = value; } } /// /// Gets or sets the list of all HTTP headers that will be used to vary cache output. /// /// /// When a cached item has several vary headers, a separate version of /// the requested document is available from the cache for each HTTP header type. /// public string VaryByHeaders { get { return varyByHeaders; } set { varyByHeaders = value; } } /// /// Gets or sets the list of parameters received by an HTTP GET or HTTP POST that affect caching. /// /// /// A separate version of the requested document is available from the cache /// for each named parameter in the VaryByParams collection. /// public string VaryByParams { get { return varyByParams; } set { varyByParams = value; } } /// /// Gets or sets the Last-Modified header HTTP header. /// public DateTime? LastModified { get { return lastModified; } set { lastModified = value; } } /// /// Gets or sets the Cache-Control: max-age HTTP header. /// public TimeSpan? MaxAge { get { return maxAge; } set { maxAge = value; } } /// /// Gets or sets the Cache-Control: s-maxage HTTP header. /// public TimeSpan? ProxyMaxAge { get { return proxyMaxAge; } set { proxyMaxAge = value; } } /// /// Gets or sets the Cache-Control must-revalidate or proxy-revalidate HTTP header. /// public HttpCacheRevalidation Revalidation { get { return revalidation; } set { revalidation = value; } } /// /// Configures ASP.Net's Cache policy based on properties set /// /// cache policy to set void ICachePolicyConfigurer.Configure(HttpCachePolicy policy) { policy.SetAllowResponseInBrowserHistory(allowInHistory); policy.SetCacheability(cacheability); policy.SetOmitVaryStar(omitVaryStar); policy.SetRevalidation(revalidation); policy.SetSlidingExpiration(slidingExpiration); policy.SetValidUntilExpires(validUntilExpires); if (duration != 0) { policy.SetExpires(DateTime.Now.AddSeconds(duration)); } #if DOTNET2SP1 || DOTNET35 if (varyByContentEncodings != null) { foreach (String header in varyByContentEncodings.Split(',')) { policy.VaryByContentEncodings[header.Trim()] = true; } } #endif if (varyByCustom != null) { policy.SetVaryByCustom(varyByCustom); } if (varyByHeaders != null) { foreach(String header in varyByHeaders.Split(',')) { policy.VaryByHeaders[header.Trim()] = true; } } if (varyByParams != null) { foreach(String param in varyByParams.Split(',')) { policy.VaryByParams[param.Trim()] = true; } } if (cacheExtension != null) { policy.AppendCacheExtension(cacheExtension); } if (setEtagFromFileDependencies) { policy.SetETagFromFileDependencies(); } if (setLastModifiedFromFileDependencies) { policy.SetLastModifiedFromFileDependencies(); } if (setNoServerCaching) { policy.SetNoServerCaching(); } if (setNoStore) { policy.SetNoStore(); } if (setNoTransforms) { policy.SetNoTransforms(); } if (etag != null) { policy.SetETag(etag); } if (lastModified != null) { policy.SetLastModified(lastModified.Value); } if (maxAge != null) { policy.SetMaxAge(maxAge.Value); } if (proxyMaxAge != null) { policy.SetProxyMaxAge(proxyMaxAge.Value); } } } }