43 votes

En-tête de dernière modification dans MVC

J'ai récemment rencontré la Dernière modification de l'en-Tête.

  • Comment et où puis-je inclure dans MVC?
  • Quels sont les avantages de l'inclusion?

Je veux un exemple de la façon dont la dernière modification de l'en-tête peut être inclus dans un projet mvc, pour les pages statiques et les requêtes de base de données ainsi?

Est-il différent de outputcache, si oui comment?

Fondamentalement, je veux le navigateur pour effacer le cache et d'afficher les données les plus récentes ou les pages automatiquement, sans la nécessité pour l'utilisateur de faire un rafraîchissement ou d'effacer le cache.

51voto

jgauffin Points 51913

L' Last-Modified est principalement utilisé pour la mise en cache. Il est renvoyé pour les ressources dont vous pouvez suivre l'heure de modification. Les ressources n'ont pas à être des fichiers, mais rien. par exemple, les pages qui sont générés à partir de dB d'information où vous avez un UpdatedAt colonne.

Il est utilisé en combinaison avec l' If-Modified-Since - tête de chaque navigateur envoie à la Demande (s'il en a reçu un Last-Modified - tête précédemment).

Comment et où puis-je inclure dans MVC?

Réponse.AddHeader

Quels sont les avantages de l'inclusion?

Permettre à grain fin de la mise en cache pour les pages sont générées dynamiquement (par exemple, vous pouvez utiliser votre champ DB UpdatedAt comme la dernière modification de l'en-tête).

Exemple

Pour faire tout ce travail que vous avez à faire quelque chose comme ceci:

public class YourController : Controller
{
    public ActionResult MyPage(string id)
    {
        var entity = _db.Get(id);
        var headerValue = Request.Headers['If-Modified-Since'];
        if (headerValue != null)
        {
            var modifiedSince = DateTime.Parse(headerValue).ToLocalTime();
            if (modifiedSince >= entity.UpdatedAt)
            {
                return new HttpStatusCodeResult(304, "Page has not been modified");
            }
        }

        // page has been changed.
        // generate a view ...

        // .. and set last modified in the date format specified in the HTTP rfc.
        Response.AddHeader('Last-Modified', entity.UpdatedAt.ToUniversalTime().ToString("R"));
    }
}

Vous pourriez avoir à spécifier un format DateTime.L'analyser.

Références:

Clause de non-responsabilité: je ne sais pas si ASP.NET/MVC3 prend en charge que vous gérez Last-Modified par vous-même.

Mise à jour

Vous pouvez créer une méthode d'extension:

public static class CacheExtensions
{
    public static bool IsModified(this Controller controller, DateTime updatedAt)
    {
        var headerValue = controller.Request.Headers['If-Modified-Since'];
        if (headerValue != null)
        {
            var modifiedSince = DateTime.Parse(headerValue).ToLocalTime();
            if (modifiedSince >= updatedAt)
            {
                return false;
            }
        }

        return true;
    }

    public static ActionResult NotModified(this Controller controller)
    {
        return new HttpStatusCodeResult(304, "Page has not been modified");
    }   
}

Et puis, les utiliser comme ceci:

public class YourController : Controller
{
    public ActionResult MyPage(string id)
    {
        var entity = _db.Get(id);
        if (!this.IsModified(entity.UpdatedAt))
            return this.NotModified();

        // page has been changed.
        // generate a view ...

        // .. and set last modified in the date format specified in the HTTP rfc.
        Response.AddHeader('Last-Modified', entity.UpdatedAt.ToUniversalTime().ToString("R"));
    }
}

19voto

Mark Points 12663


Mise à JOUR: Vérifier ma nouvelle réponse


Comment et où puis-je inclure dans MVC?

Le haut- OutputCache filtre fait le travail pour vous et il utilise ces en-têtes pour la mise en cache. L' OuputCache filtre utilise l' Last-Modified - tête lorsque vous définissez l' Location comme Client ou ServerAndClient.

[OutputCache(Duration = 60, Location = "Client")]
public ViewResult PleaseCacheMe()
{
    return View();
}

Quels sont les avantages de l'inclusion?

Tirant parti de la mise en cache côté client avec conditionnelle de vidage du cache

Je veux un exemple de la façon dont la dernière modification de l'en-tête peut être inclus dans un projet mvc, pour les pages statiques et les requêtes de base de données ainsi?

Ce lien contient suffisamment d'informations pour essayer un échantillon. Pour les pages statiques comme le html, les images IIS prendra soin de réglage/vérification de l' Last-Modified - tête et il utilise le fichier de la dernière date de modification. Pour les requêtes de base de données, vous pouvez aller pour le réglage de la SqlDependency dans la OutputCache.

Est-ce différent pour outputcache, si oui comment? Quand dois-je inclure-Tête Last-Modified et quand utiliser outputcache?

OutputCache est une action de filtre utilisé pour la mise en œuvre de mécanisme de mise en cache dans ASP.NET MVC. Il ya différentes façons que vous pourriez effectuer la mise en cache à l'aide de OutputCache: mise en cache côté client, côté serveur de mise en cache. Last-Modified - tête est un moyen pour accomplir mise en cache côté client. OutputCache filtre utilise lorsque vous définissez l' Location comme Client.

Si vous allez pour la mise en cache côté client (Last-Modified ou ETag) le cache du navigateur sera automatiquement mis à jour dans la demande ultérieure, et vous n'avez pas besoin de faire F5.

16voto

Lukas Winzenried Points 1279

Dernière modification vs OutputCache

Le OutputCache attribut détermine la mise en cache de sortie sur votre Serveur web IIS. C'est un fournisseur de serveur (se reporter à la configuration de IIS 7 mise en Cache de Sortie). Je suggère également de lire le Cache de l'Exploration ASP.NET MVC3 si vous êtes intéressés par les puissantes capacités de cette technologie.

Last-Modified - tête de réponse et c'est de contrepartie Si-Modified-since - tête de la requête sont les représentants de la validation du cache concept (section de contrôle de cache). Ces en-têtes sont une partie du protocole HTTP et spécifié dans rfc4229

OutputCache et de validation ne sont pas exclusives, vous pouvez les combiner.

Ce que cache le scénario qui me rend heureux?

Comme d'habitude: ça dépend.

La configuration d'un 5 deuxième OutputCache à 100 coups/seconde page de réduire considérablement la charge. À l'aide de OutputCache, 499 de 500 hits peut être servi de cache (et ne coûtent pas db aller-retour, les calculs de rendu).

Lorsque j'ai pour servir rarement des modifications immédiatement, puis la validation du scénario pourrait sauver beaucoup de bande passante. Spécialement quand vous servir de contenu de grande taille par rapport à un lean 304 message d'état. Cependant, les modifications sont adoptées immédiatement, car chaque demande valide pour des changements dans la source.

Dernière modification de l'attribut de mise en œuvre de l'échantillon

D'après mon expérience, je vous recommande de mettre en œuvre la validation du scénario (dernière modification) comme une action de filtre d'attribut. (Btw: Ici's une mise en cache d'autres scénario mis en œuvre comme un attribut)

Le contenu statique à partir d'un fichier

[LastModifiedCache]
public ActionResult Static()
{
    return File("c:\data\static.html", "text/html");
}

Le contenu dynamique de l'échantillon

[LastModifiedCache]
public ActionResult Dynamic(int dynamicId)
{
    // get data from your backend (db, cache ...)
    var model = new DynamicModel{
        Id = dynamivId,
        LastModifiedDate = DateTime.Today
    };
    return View(model);
}

public interface ILastModifiedDate
{
    DateTime LastModifiedDate { get; }
}

public class DynamicModel : ILastModifiedDate
{
    public DateTime LastModifiedDate { get; set; }
}

Le LastModifiedCache attribut

public class LastModifiedCacheAttribute : ActionFilterAttribute 
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is FilePathResult)
        {
            // static content is served from file in my example
            // the last file write time is taken as modification date
            var result = (FilePathResult) filterContext.Result;
            DateTime lastModify = new FileInfo(result.FileName).LastWriteTime;

            if (!HasModification(filterContext.RequestContext, lastModify))
                filterContext.Result = NotModified(filterContext.RequestContext, lastModify);
            SetLastModifiedDate(filterContext.RequestContext, lastModify);
        }

        if (filterContext.Controller.ViewData.Model is HomeController.ILastModifiedDate)
        {
            // dynamic content assumes the ILastModifiedDate interface to be implemented in the model
            var modifyInterface = (HomeController.ILastModifiedDate)filterContext.Controller.ViewData.Model;
            DateTime lastModify = modifyInterface.LastModifiedDate;

            if (!HasModification(filterContext.RequestContext, lastModify))
                filterContext.Result = NotModified(filterContext.RequestContext, lastModify);
            filterContext.RequestContext.HttpContext.Response.Cache.SetLastModified(lastModify);
        }

        base.OnActionExecuted(filterContext);
    }

    private static void SetLastModifiedDate(RequestContext requestContext, DateTime modificationDate)
    {
        requestContext.HttpContext.Response.Cache.SetLastModified(modificationDate);
    }

    private static bool HasModification(RequestContext context, DateTime modificationDate)
    {
        var headerValue = context.HttpContext.Request.Headers["If-Modified-Since"];
        if (headerValue == null)
            return true;

        var modifiedSince = DateTime.Parse(headerValue).ToLocalTime();
        return modifiedSince < modificationDate;
    }

    private static ActionResult NotModified(RequestContext response, DateTime lastModificationDate)
    {
        response.HttpContext.Response.Cache.SetLastModified(lastModificationDate);
        return new HttpStatusCodeResult(304, "Page has not been modified");
    }
}

Comment faire pour activer la fonction global LastModified soutien

Vous pouvez ajouter la LastModifiedCache attribut à la RegisterGlobalFilters section globale de votre.asax.cs pour activer globalement ce type de mise en cache dans votre projet mvc.

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    ...
    filters.Add(new LastModifiedCacheAttribute());
    ...
}

1voto

Mark Points 12663

C'est ma deuxième réponse après avoir fait quelques recherches sur la mise en cache et OutputCache.

Permettez-moi de répondre à votre deuxième question.

Quels sont les avantages de l'inclusion?

Navigateur met en cache les réponses retournées par le serveur. La mise en cache est contrôlée principalement par trois en-têtes: Cache-Control, Last-Modified et Expires (il y en a d'autres, comme ETag aussi vient de jouer).

L' Last-Modified - tête indique au navigateur lorsque la ressource a été modifiée à la dernière. La ressource peut être soit statique fichier ou créés dynamiquement vue. Chaque fois que le navigateur fait la demande pour cette ressource, il vérifie avec le serveur "Hé, j'ai déjà une réponse à cette demande et il est Last-Modified date est ainsi.. voir l'utilisateur est déjà fatigué... si vous retournez un 304 je suis heureux de pouvoir utiliser la réponse de mon cache reste s'il vous plaît envoyez votre réponse rapide". (Notez que le navigateur transmet l' Last-Modified de la valeur retournée par le serveur dans un nouvel en-tête appelé If-Modified-Since)

Idéalement, le serveur doit lire la valeur de l' If-Modified-Since - tête et a vérifier avec le courant de la date de modification et si elles sont les mêmes, alors il devrait retourner 304 (NON MODIFIÉ) ou alors, il faut retourner la nouvelle copie de la ressource passant à nouveau le courant de la date de modification dans l' Last-Modified - tête.

L'avantage est mise en cache du navigateur. En tirant parti de la mise en cache du navigateur, le serveur peut éviter de créer un doublon de réponse et il peut aussi renvoyer une nouvelle réponse si la réponse en cache dans le navigateur ressemble à de vieux. Le but ultime est de gagner du temps.

Comment et où puis-je inclure dans MVC?

Dans le cas des ressources statiques (images, fichiers html et d'autres que vous n'avez pas besoin de vous soucier des réglages Comment et parce qu' IIS se charge de travail. IIS utilise le fichier de la date de la dernière modification que l' Last-Modified valeur d'en-tête.

Dans le cas de pages dynamiques comme un contenu html retourné par l'intermédiaire d'un MVC action, comment vous pouvez déterminer le Last-Modified valeur d'en-tête? La dynamique des pages dynamiques sont pour la plupart fondés sur des données et il est de notre responsabilité de décider si la réponse renvoyée est déjà obsolète ou pas.

Disons que vous avez un blog et vous avez une page si vous affichez les détails d'un article (et pas tous les autres détails), puis la page de la version est décidé par la date de dernière modification ou de la date de création (si l'article n'est pas modifié encore) de l'article. De sorte que vous avez à faire le même travail répondu par @jgauffin dans l'action correspondante qui offre la vue.

Vous avez demandé dans les commentaires Devrais-je inclure par action dans le contrôleur?

Si vous pouviez en mesure de faire abstraction de la logique de la lecture de la dernière date de modification de la base de données des actions alors que vous pourriez accomplir le travail par le biais d'un filtre d'actions d'éviter la duplication du code à travers des actions. La question est de savoir comment vous allez faire abstraction des détails loin d'actions? Comme passer de la table/les noms de colonnes à l'attribut? Vous devez le comprendre!

Comme un exemple..

[LastModifiedCacheFilter(Table = "tblArticles", Column = "last_modified")]
public ViewResult Post(int postId)
{
   var post = ... get the post from database using the postId
   return View(post);
}

Le pseudo-code (ce qui signifie que je n'ai pas testé :) de l' LastModifiedCacheFilterAttribute mise en œuvre montré ci-dessous utilise la Table/Colonne de lire la date de dernière modification, mais ça peut être quelques autres façons. L'idée est dans l' OnActionExecuting méthode que nous faisons de la vérification et le retour d'un 304 (si le cache est encore frais) et dans l' OnResultExecuted méthode que nous lecture/réglage de la dernière date de modification.

public class LastModifiedCacheFilterAttribute : ActionFilterAttribute
{
    // Could be some other things instead of Table/Column
    public string Table { get; set; }
    public string Column { get; set; }    

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
      // var lastModified = read the value from the passed Column/Table and set it here 

      var ifModifiedSinceHeader = filterContext.RequestContext.HttpContext.Request.Headers["If-Modified-Since"];

      if (!String.IsNullOrEmpty(ifModifiedSinceHeader))
      {
        var modifiedSince = DateTime.Parse(ifModifiedSinceHeader).ToLocalTime();
        if (modifiedSince >= lastModified)
        {
          filterContext.Result = new EmptyResult();
          filterContext.RequestContext.HttpContext.Response.Cache.SetLastModified(lastModified.ToUniversalTime());
          filterContext.RequestContext.HttpContext.Response.StatusCode = 304;
        }
      }

      base.OnActionExecuting(filterContext);
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
      // var lastModified = read the value from the passed Column/Table and set it herefilterContext.RequestContext.HttpContext.Response.Cache.SetLastModified(lastModified.ToUniversalTime());
      base.OnResultExecuted(filterContext);
    }
}

Pourquoi ne peut-OutputCache attribut?

Selon mon analyse, OutputCache attribut n'utilise pas les Last-Modified mécanisme de mise en cache. L'autre chose, c'est qu'il utilise l'ancienne page mécanisme de mise en cache ce qui rend difficile pour personnaliser/prolonger.

Avez-vous vraiment besoin de mettre en œuvre la dernière modification du mécanisme dans toutes vos actions?

Vraiment pas nécessaire. Vous pourriez mettre en œuvre la dernière modification du mécanisme pour les actions qui prend plus de temps pour créer une telle réponse, et il faut plus de temps pour voyager la réponse en bas de la fil et de la portée du navigateur. Dans d'autres cas, je me sens juste un rétroprojecteur tout au long de la mise en œuvre de toutes les actions et aussi que vous avez à mesurer les avantages avant de le faire. L'autre point principal est, dans de nombreux cas la version de la page est pas décidé par une seule colonne de la table , il pourrait être beaucoup d'autres choses et dans ce cas, il peut être plus compliqué à mettre en œuvre cette!

Un point sur l' ETag

Bien que la question est à propos de Last-Modified - tête que je devrais dire quelque chose à propos de ETag avant de cliquer sur le Post de Votre Réponse bouton. Comparé à d' Last-Modified (qui s'appuie sur datetime) en-tête ETag - tête (s'appuie sur une valeur de hachage) est plus précise de déterminer si la réponse en cache dans le navigateur est frais ou pas, mais il pourrait être un peu compliqué à mettre en œuvre. IIS comprend également ETag - tête avec l' Last-Modified - tête pour les ressources statiques. Avant de mettre en œuvre toute de ce mécanisme de google et de voir s'il existe une bibliothèque qui vous permet de sortir!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X