Par défaut, un ensemble MVC est mis en cache sur le client pendant un an. Est-il possible de définir ses en-têtes client manuellement (pour 1 lot spécifique)?
Ce dont j'ai besoin, c'est de définir des en-têtes d'expiration personnalisés pour l'un de mes ensembles. Je ne peux pas compter sur la chaîne de requête "v = hash", car cette offre est destinée à un site Web externe et ne modifie pas l'URL pointant vers mon offre chaque fois que je le modifie.
Ce que j'ai essayé, c'est de créer une classe Bundle personnalisée (inherit Bundle) et de remplacer la méthode GenerateBundleResponse (). De cette façon, je peux contrôler la mise en cache du serveur, mais la seule façon de personnaliser la mise en cache du client consiste à définir BundleResponse.Cacheability (public, privé, nocache, etc.). Mais je ne peux pas définir les en-têtes manuellement. J'ai accès à BundleContext (et à HttpContext), mais lorsque je mets des en-têtes dans ce contexte, cela s'applique également à toutes les autres demandes.
Malheureusement, il n'y a pas moyen. Vous pouvez trouver le motif dans l'implémentation interne du groupement. Dans la classe BundleHandler
, ProcessRequest appelle la méthode interne ProcessRequest
de la classe Bundle
et elle appelle SetHeaders juste avant le HttpContext.Response.Write
. Par conséquent, le cache du client est défini sur un an juste avant l'écriture de la réponse.
Remarque: BundleHandler
est une classe interne scellée: internal sealed class BundleHandler : IHttpHandler
Dans la classe BundleHandler
:
public void ProcessRequest(HttpContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
context.Response.Clear();
BundleContext context2 = new BundleContext(new HttpContextWrapper(context), BundleTable.Bundles, this.BundleVirtualPath);
if (!Bundle.GetInstrumentationMode(context2.HttpContext) && !string.IsNullOrEmpty(context.Request.Headers["If-Modified-Since"]))
{
context.Response.StatusCode = 304;
}
else
{
this.RequestBundle.ProcessRequest(context2);
}
}
Dans la classe Bundle
:
internal void ProcessRequest(BundleContext context)
{
context.EnableInstrumentation = GetInstrumentationMode(context.HttpContext);
BundleResponse bundleResponse = this.GetBundleResponse(context);
SetHeaders(bundleResponse, context);
context.HttpContext.Response.Write(bundleResponse.Content);
}
private static void SetHeaders(BundleResponse bundle, BundleContext context)
{
if (bundle.ContentType != null)
{
context.HttpContext.Response.ContentType = bundle.ContentType;
}
if (!context.EnableInstrumentation)
{
HttpCachePolicyBase cache = context.HttpContext.Response.Cache;
cache.SetCacheability(bundle.Cacheability);
cache.SetOmitVaryStar(true);
cache.SetExpires(DateTime.Now.AddYears(1));
cache.SetValidUntilExpires(true);
cache.SetLastModified(DateTime.Now);
cache.VaryByHeaders["User-Agent"] = true;
}
}
Le comportement par défaut de la fonctionnalité de regroupement ASP.NET MVC est le suivant: si l'un des fichiers composant un regroupement change, la chaîne de requête de ce regroupement change automatiquement, à condition que vous utilisiez les éléments suivants dans le code de votre vue:
@Scripts.Render("bundle name")
Cela signifie donc que si vous avez une nouvelle version d'un fichier dans un ensemble, la prochaine fois que votre page affichera un affichage utilisant cet ensemble, elle enverra une balise de script que le navigateur client ne trouvera pas dans son cache (car la chaîne de requête est différente).
Il semble donc que cela résoudra votre problème - cela dépend de ce que vous entendez par:
et ils ne changeront pas l'URL pointant sur mon paquet chaque fois que je changerai il
Bien qu'il n'y ait pas de meilleur moyen de configurer la mise en cache des ensembles, vous pouvez créer un HttpModule qui identifie les demandes de l'ensemble et définit la mise en cache du contenu.
Vous avez le même effet en faisant cela sur le fichier Global.asax:
public override void Init()
{
this.EndRequest += MvcApplication_EndRequest;
base.Init();
}
void MvcApplication_EndRequest(object sender, EventArgs e)
{
var request = this.Request;
var response = this.Response;
if (request.RawUrl.Contains("Content/"))
{
response.Cache.SetCacheability(HttpCacheability.NoCache);
}
}
Ce qui semble fonctionner pour moi, c'est donner un numéro de version au paquet dans la configuration du paquet, puis référencer la nouvelle version dans votre balisage.
Ceci est une modification de la réponse d'Adilson, mais sans avoir à créer un HttpModule:
Dans le fichier global.asax.cs du projet MVC:
protected void Application_EndRequest(object sender, EventArgs e) {
if (Request.RawUrl.Contains("/bundles/")) {
// My bundles all have a /bundles/ prefix in the URL
Response.Cache.SetExpires(DateTime.Now.AddHours(2));
}
}
Transmettez un paramètre de chaîne de requête supplémentaire dans l'URL et modifiez-le chaque fois que vous souhaitez que le cache soit actualisé.
exemple: https://www.google.co.in/?gfe_rd=cr&ei=EwJeVbHWLcX08wfgwoCoBA&gws_rd=ssl&custom=abc
le dernier paramètre est personnalisé.