問題について言及している codeplex リンクで説明されているのと同じ動作が見られました。
つまり、次の順序でこれらの URL にアクセスすると、動作は次のようになります。
bundle.css?v=1234 : no-cache
bundle.css : public
bundle.css?v=1234 : public
System.Web.Optimization のソース コードを少し掘り下げて、何が起こっているのかを確認することにしました。Bundle クラスには、ヘッダーを設定するプライベート メソッドがあり、次のコードに該当するようです。
if (noCache) {
cachePolicy.SetCacheability(HttpCacheability.NoCache);
}
noCache 変数は、パラメーターを介して設定されます。この場合の呼び出し方法はそれを設定しています:
// Set to no-cache if the version requested does not match
bool noCache = false;
var request = context.HttpContext.Request;
if (request != null) {
string queryVersion = request.QueryString.Get(VersionQueryString);
if (queryVersion != null && bundleResponse.GetContentHashCode() != queryVersion) {
noCache = true;
}
}
簡単に言うと、バンドルに Azure CDN を使用するように切り替え、バージョン クエリ文字列パラメーターをアセンブリ バージョンに基づいて ?v=1.0.0.0 のようなものに変更しました (この質問に似ています)。バンドル コードは、「1.0.0.0」をバンドル コンテンツの SHA256 ハッシュ コードと比較し、その結果、バンドルにキャッシュなしのフラグを立てています。
コンテンツ ハッシュと一致するようにクエリ文字列を更新することで、これを解決しました。
残念ながら、GetContentHashCode メソッドのアクセス レベルは internal とマークされているため、実装を複製する必要がありました。最終的に、Bundle から継承したクラスを作成して、バージョン番号を変換として CdnPath に適用できるようにしました。
public class ProxiedCdnBundle : Bundle
{
private readonly string _cdnHost;
public ProxiedCdnBundle(string virtualPath, string cdnHost = "")
: base(virtualPath)
{
_cdnHost = cdnHost;
}
public override BundleResponse ApplyTransforms(BundleContext context, string bundleContent, IEnumerable<BundleFile> bundleFiles)
{
var response = base.ApplyTransforms(context, bundleContent, bundleFiles);
if (context.BundleCollection.UseCdn && !String.IsNullOrWhiteSpace(_cdnHost))
{
string path = System.Web.VirtualPathUtility.ToAbsolute(context.BundleVirtualPath);
base.CdnPath = string.Format("{0}{1}?v={2}", _cdnHost, path, GetBundleHash(response));
}
return response;
}
private static string GetBundleHash(BundleResponse response)
{
using (var hashAlgorithm = CreateHashAlgorithm())
{
return HttpServerUtility.UrlTokenEncode(hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(response.Content)));
}
}
private static SHA256 CreateHashAlgorithm()
{
if (CryptoConfig.AllowOnlyFipsAlgorithms)
{
return new SHA256CryptoServiceProvider();
}
return new SHA256Managed();
}
}