Подтвердить что ты не робот

Кэширование клиента MVC

По умолчанию пакет MVC кэшируется на клиенте в течение 1 года. Можно ли вручную настроить его для заголовков клиентов (для одного конкретного пакета)?

Мне нужно установить пользовательские заголовки истечения для одного из моих пакетов. Я не могу полагаться на "v = hash" querystring, потому что этот пакет предназначен для внешнего веб-сайта, и они не будут изменять URL-адрес, указывающий на мой пакет, каждый раз, когда я его изменяю.

Я попытался создать собственный класс Bundle (наследовать Bundle) и переопределить метод GenerateBundleResponse(). Таким образом, я могу контролировать кеширование сервера, но единственным способом настройки кэширования клиентов является установка BundleResponse.Cacheability(общедоступный, закрытый, nocache и т.д.). Но я не могу настроить заголовки вручную. У меня есть доступ к BundleContext (и это HttpContext), но когда я устанавливаю заголовки в этом контексте, это будет иметь влияние и на все остальные запросы.

4b9b3361

Ответ 1

К сожалению, нет способа. Вы можете найти причину во внутренней реализации комплектации. в классе BundleHandler ProcessRequest вызывает ProcessRequest, внутренний метод класса Bundle и вызывает SetHeaders непосредственно перед HttpContext.Response.Write. Поэтому кеш клиента устанавливается на один год перед записью ответа.

Примечание: BundleHandler - это внутренний закрытый класс: internal sealed class BundleHandler : IHttpHandler

В классе 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);
    }
}

В классе 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;
    }
}

Ответ 2

Поведение ASP.NET MVC по умолчанию по умолчанию заключается в том, что если какой-либо из файлов, которые составляют изменение пакета, строка запроса для этого пакета автоматически изменится - если вы используете в своем коде зрения следующее:

@Scripts.Render("bundle name")

Итак, это означает, что если у вас есть новая версия файла, который находится в комплекте, то в следующий раз, когда ваша страница отобразит представление, которое использует этот пакет, оно отправит тег script, который браузер клиента не найдет в его кеш (поскольку строка запроса отличается).

Итак, похоже, что это решит вашу проблему - зависит от того, что вы подразумеваете под:

и они не изменят URL-адрес, указывающий на мой пакет, каждый раз, когда я меняю это

Ответ 3

Хотя нет лучшего способа настройки кеширования пакетов, вы можете создать HttpModule, который идентифицирует запросы к набору и задает кеширование содержимого.

У вас есть тот же эффект, что и на 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);
        }
    }

Ответ 4

Кажется, что для меня работает пакет, содержащий номер версии в конфигурации пакета, а затем ссылку на новую версию в вашей разметке.