Ho un controller API Web ASP.Net che restituisce semplicemente l'elenco di utenti.Come utilizzare ETag in Web API utilizzando il filtro azione insieme a HttpResponseMessage
public sealed class UserController : ApiController
{
[EnableTag]
public HttpResponseMessage Get()
{
var userList= this.RetrieveUserList(); // This will return list of users
this.responseMessage = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ObjectContent<List<UserViewModel>>(userList, new JsonMediaTypeFormatter())
};
return this.responseMessage;
}
}
e un filtro azione attributo class EnableTag
che è responsabile per la gestione e la cache ETag:
public class EnableTag : System.Web.Http.Filters.ActionFilterAttribute
{
private static ConcurrentDictionary<string, EntityTagHeaderValue> etags = new ConcurrentDictionary<string, EntityTagHeaderValue>();
public override void OnActionExecuting(HttpActionContext context)
{
if (context != null)
{
var request = context.Request;
if (request.Method == HttpMethod.Get)
{
var key = GetKey(request);
ICollection<EntityTagHeaderValue> etagsFromClient = request.Headers.IfNoneMatch;
if (etagsFromClient.Count > 0)
{
EntityTagHeaderValue etag = null;
if (etags.TryGetValue(key, out etag) && etagsFromClient.Any(t => t.Tag == etag.Tag))
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotModified);
SetCacheControl(context.Response);
}
}
}
}
}
public override void OnActionExecuted(HttpActionExecutedContext context)
{
var request = context.Request;
var key = GetKey(request);
EntityTagHeaderValue etag;
if (!etags.TryGetValue(key, out etag) || request.Method == HttpMethod.Put || request.Method == HttpMethod.Post)
{
etag = new EntityTagHeaderValue("\"" + Guid.NewGuid().ToString() + "\"");
etags.AddOrUpdate(key, etag, (k, val) => etag);
}
context.Response.Headers.ETag = etag;
SetCacheControl(context.Response);
}
private static void SetCacheControl(HttpResponseMessage response)
{
response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromSeconds(60),
MustRevalidate = true,
Private = true
};
}
private static string GetKey(HttpRequestMessage request)
{
return request.RequestUri.ToString();
}
}
Il codice precedente crea una classe attributo per gestire ETag. Quindi, alla prima richiesta, creerà un nuovo E-Tag e per la successiva richiesta controllerà se esiste ETag. in caso affermativo, genererà lo stato HTTP Not Modified
e tornerà al client.
Il mio problema è, voglio creare un nuovo ETag se ci sono cambiamenti nella mia lista utenti, es. viene aggiunto un nuovo utente o viene eliminato un utente esistente. e aggiungilo alla risposta. Questo può essere tracciato dalla variabile userList
.
Attualmente, l'ETag ricevuto dal client e dal server è lo stesso da ogni seconda richiesta, quindi in questo caso genererà sempre lo stato Not Modified
, mentre lo voglio quando effettivamente non è cambiato nulla.
Qualcuno può guidarmi in questa direzione? Grazie in anticipo.
Questo è perfetto: offre una soluzione etag per le chiamate webapi senza la necessità di bufferizzare la risposta, riducendo le prestazioni, come fanno le soluzioni di checksum. –