Кэширование веб-API ASP.NET с помощью CacheCow

Я пытаюсь реализовать кэширование с помощью CacheCow. У меня две проблемы:

  • В некоторых случаях мне нужно вручную аннулировать кеш-память некоторых ресурсов.

    Например, у меня есть ресурс, который он называется purchase, и другой, который называется pointMovements. Они не полностью связаны, но запись в purchase подразумевает некоторые изменения в pointMovement. Cachecow не обнаруживает эти изменения, потому что я не называю API pointMovements. Поэтому, когда я вызываю конечную точку pointMovements, значения кэшируются, и я не могу получить новые значения.

    Чтобы решить эту проблему, мне нужно сделать это вручную, как это возможно?

  • Есть несколько контроллеров, которые я не хочу кэшировать. Я пытаюсь использовать атрибуты для этого, но он не работает. Я следую этой статье, но атрибуты игнорируются.

    Как указать, какие контроллеры кэшировать?

Ответы

Ответ 1

Я столкнулся с одним и тем же набором проблем и нашел решение проблемы 2 (отключить кеширование, независимо от настроек по умолчанию).

// This forces the server to not provide any caching by refreshing its cache table immediately (0 sec)
[HttpCacheRefreshPolicy(0)]
// This forces the client (browser) to not cache any data returned from the server (even if ETag is present) by setting the time-out to 0 and no-cache to true.
[HttpCacheControlPolicy(true, 0, true)]
public void MyController : ApiControler {... }

Атрибуты должны применяться вместе, чтобы это работало. Вы также можете контролировать кеширование на уровне действия, предоставляя одинаковые правила для каждого действия.

Мне еще нужно выяснить решение проблемы 1. но посмотрите это пространство для обновлений.

Обновление Я нашел решение проблемы 1.

  • Зарегистрируйте CachingHandler с помощью контейнера IoC (в моем случае это IUnityContainer)
  • Внедрение ICachingHandler в ваш контроллер веб-API.
  • Чтобы недействить ресурс, используйте ICachingHandler.InvalidateResource(HttpRequestMessage)

См. пример кода ниже. Решение было протестировано.

pubic class Bootstrapper
{
    //...

    // Create a new caching handler and register it with the container.
    public void RegisterCache(HttpConfiguration config, IUnityContainer container)
    {
        var cachingHandler = new CachingHandler(config);
        // ...

        container.RegisterInstance<ICachingHandler>(cachingHandler);
    }
}

public class ResourceContoller : ApiController
{
    private ICachingHandler _cachingHandler;

    public ResourceContoller(ICachingHandler cachingHandler)
    {
        _cachingHandler = cachingHandler;       
    }

    [HttpPost]
    public void DeleteResource(int resourceId)
    {
        // Do the delete
        // ...

        // Now invalidate the related resource cache entry      
        // Construct a http request message to the related resource
        // HINT: The "DefaultApi" may not be your api route name, so change this to match your route.
        // GOTCHA: The route matching mechanism is case sensitive, so be aware!
        var relatedResource = new HttpRequestMessage(HttpMethod.Get, Url.Link("DefaultApi", new {controller = "linkedresource", action = "getlinkedresource", id: resourceId}));

        // Invalidate the resource with the caching handler.
        _cachingHandler.InvalidateResource(relatedResource);
    }
}

Ответ 3

Я решил ваш вопрос №1, используя нижеприведенный код. Здесь я расширяю интерфейс IRoutePatternProvider. Помните, что вы вернетесь в GetRoutePattern должны соответствовать тому, что вы возвращаете в GetLinkedRoutePatterns. Только тогда добавление и удаление будут работать. Попробуйте.

Внутри Application_Start

CachingHandler cacheHandler = new CachingHandler(GlobalConfiguration.Configuration);
        cacheHandler.RoutePatternProvider = new CacheRoutePatternProvider();
        GlobalConfiguration.Configuration.MessageHandlers.Add(cacheHandler);

Пользовательский класс

public class CacheRoutePatternProvider : IRoutePatternProvider
{
    public string GetRoutePattern(HttpRequestMessage request)
    {
        string path = request.RequestUri.AbsolutePath;
        if (!path.EndsWith("/"))
            path += "/";

        return path;
    }

    public IEnumerable<string> GetLinkedRoutePatterns(HttpRequestMessage request)
    {
        string path = request.RequestUri.AbsolutePath;
        if(!path.EndsWith("/"))
            path += "/";

        int segmentIndex;
        // return each segment of the resource heirarchy
        while ((segmentIndex = path.LastIndexOf("/")) > 0)
        {
            path = path.Substring(0, segmentIndex);

            if(path.Contains("/api/"))
                yield return path + "/";
        }

        yield break;
    }
}