web-dev-qa-db-fra.com

Mise en cache de sortie pour un ApiController (API Web MVC4)

J'essaie de mettre en cache la sortie d'une méthode ApiController dans l'API Web.

Voici le code du contrôleur:

public class TestController : ApiController
{
    [OutputCache(Duration = 10, VaryByParam = "none", Location = OutputCacheLocation.Any)]
    public string Get()
    {
        return System.DateTime.Now.ToString();
    }
}

N.B. J'avais également essayé l'attribut OutputCache sur le contrôleur lui-même, ainsi que plusieurs combinaisons de ses paramètres.

L'itinéraire est enregistré dans Global.asax:

namespace WebApiTest
{
    public class Global : HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {
            RouteTable.Routes.MapHttpRoute("default", routeTemplate: "{controller}");
        }
    }
}

J'obtiens une réponse réussie, mais elle n'est mise en cache nulle part:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 18 Jul 2012 17:56:17 GMT
Content-Length: 96

<string xmlns="http://schemas.Microsoft.com/2003/10/Serialization/">18/07/2012 18:56:17</string>

Je n'ai pas pu trouver de documentation pour la mise en cache de sortie dans l'API Web.

Est-ce une limitation de l'API Web dans MVC4 ou est-ce que je fais quelque chose de mal?

46
Samu Lang

WebAPI n'a pas de support intégré pour le [OutputCache] attribut. Prenez jetez un œil à cet article pour voir comment vous pouvez implémenter cette fonctionnalité vous-même.

40
Cory

La réponse d'Aliostad indique que l'API Web désactive la mise en cache et le code de HttpControllerHandler indique qu'il le fait QUAND la réponse.Headers.CacheControl est nulle.

Pour que votre exemple d'Action ApiController renvoie un résultat pouvant être mis en cache, vous pouvez:

using System.Net.Http;

public class TestController : ApiController
{
    public HttpResponseMessage Get()
    {
        var response = Request.CreateResponse(HttpStatusCode.OK);
        response.Content = new StringContent(System.DateTime.Now.ToString());
        response.Headers.CacheControl = new CacheControlHeaderValue();
        response.Headers.CacheControl.MaxAge = new TimeSpan(0, 10, 0);  // 10 min. or 600 sec.
        response.Headers.CacheControl.Public = true;
        return response;
    }
}

et vous obtiendrez un en-tête de réponse HTTP comme celui-ci:

Cache-Control: public, max-age=600
Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Date: Wed, 13 Mar 2013 21:06:10 GMT
...
33
Luciano Carvalho

Depuis quelques mois, je travaille sur la mise en cache HTTP pour l'API Web ASP.NET. J'ai contribué à WebApiContrib pour le côté serveur et des informations pertinentes peuvent être trouvées sur mon blog .

Récemment, j'ai commencé à étendre le travail et à ajouter le côté client également dans la bibliothèque CacheCow . Les premiers packages NuGet sont maintenant disponibles (merci à Tugberk ) Plus à venir. J'écrirai bientôt un blog à ce sujet. Alors surveillez l'espace.


Mais pour répondre à votre question, l'API Web ASP.NET désactive par défaut la mise en cache. Si vous souhaitez que la réponse soit mise en cache, vous devez ajouter l'en-tête CacheControl à la réponse dans votre contrôleur (et en fait il vaut mieux être dans un gestionnaire de délégation similaire à CachingHandler dans CacheCow).

Cet extrait provient de HttpControllerHandler dans le code source ASP.NET Web Stack:

        CacheControlHeaderValue cacheControl = response.Headers.CacheControl;

        // TODO 335085: Consider this when coming up with our caching story
        if (cacheControl == null)
        {
            // DevDiv2 #332323. ASP.NET by default always emits a cache-control: private header.
            // However, we don't want requests to be cached by default.
            // If nobody set an explicit CacheControl then explicitly set to no-cache to override the
            // default behavior. This will cause the following response headers to be emitted:
            //     Cache-Control: no-cache
            //     Pragma: no-cache
            //     Expires: -1
            httpContextBase.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        }
15
Aliostad

Je suis très en retard, mais j'ai quand même pensé à publier cet excellent article sur la mise en cache dans WebApi

https://codewala.net/2015/05/25/outputcache-doesnt-work-with-web-api-why-a-solution/

public class CacheWebApiAttribute : ActionFilterAttribute
{
    public int Duration { get; set; }

    public override void OnActionExecuted(HttpActionExecutedContext filterContext)
    {
        filterContext.Response.Headers.CacheControl = new CacheControlHeaderValue()
        {
            MaxAge = TimeSpan.FromMinutes(Duration),
            MustRevalidate = true,
            Private = true
        };
    }
}

Dans le code ci-dessus, nous avons remplacé la méthode OnActionExecuted et défini l'en-tête requis dans la réponse. Maintenant, j'ai décoré l'appel de l'API Web comme

[CacheWebApi(Duration = 20)]
        public IEnumerable<string> Get()
        {
            return new string[] { DateTime.Now.ToLongTimeString(), DateTime.UtcNow.ToLongTimeString() };
        }
2
himanshupareek66