forçar os navegadores a obter os arquivos js e css mais recentes no aplicativo asp.net

104

Alguns navegadores armazenam arquivos js e css em cache, deixando de atualizá-los, a menos que você os force a fazer isso. Qual é a maneira mais fácil.

Acabei de implementar esta solução que parece funcionar.

Declare uma variável de versão em sua página

  public string version { get; set; }

Obtenha o número da versão da chave web.config

 version = ConfigurationManager.AppSettings["versionNumber"];

Em sua página aspx, faça chamadas para javascript e folhas de estilo assim

<script src="scripts/myjavascript.js?v=<%=version %>" type="text/javascript"></script>
<link href="styles/mystyle.css?v=<%=version %>" rel="stylesheet" type="text/css" />

Portanto, se você definir a versão = 1.1 de 1.0 em seu web.config, seu navegador fará o download dos arquivos mais recentes, o que, com sorte, evitará que você e seus usuários frustem alguma coisa.

Existe outra solução que funcione melhor ou isso causará problemas imprevistos para um site?

kiev
fonte
Pergunta interessante, tive o mesmo problema recentemente, mas era apenas um problema durante os testes de desenvolvimento. Não me importei muito com isso, pois não temos a intenção de alterar esses arquivos após o lançamento. Adoraria saber uma solução para referência futura!
Brett Allen
O único problema que vejo é que as alterações no web.config irão, em segundo plano, chamar uma reinicialização do aplicativo: msdn.microsoft.com/en-us/library/aa478432.aspx
monty
Obrigado pela pergunta. Isso me ajudou a resolver um grande problema.
Reddy

Respostas:

76

Resolvi isso acrescentando um carimbo de data / hora da última modificação como um parâmetro de consulta aos scripts.

Eu fiz isso com um método de extensão e usando-o em meus arquivos CSHTML. Observação: esta implementação armazena em cache o carimbo de data / hora por 1 minuto para que não mexamos tanto no disco.

Aqui está o método de extensão:

public static class JavascriptExtension {
    public static MvcHtmlString IncludeVersionedJs(this HtmlHelper helper, string filename) {
        string version = GetVersion(helper, filename);
        return MvcHtmlString.Create("<script type='text/javascript' src='" + filename + version + "'></script>");
    }

    private static string GetVersion(this HtmlHelper helper, string filename)
    {
        var context = helper.ViewContext.RequestContext.HttpContext;

        if (context.Cache[filename] == null)
        {
            var physicalPath = context.Server.MapPath(filename);
            var version = $"?v={new System.IO.FileInfo(physicalPath).LastWriteTime.ToString("MMddHHmmss")}";
            context.Cache.Add(filename, version, null,
              DateTime.Now.AddMinutes(5), TimeSpan.Zero,
              CacheItemPriority.Normal, null);
            return version;
        }
        else
        {
            return context.Cache[filename] as string;
        }
    }
}

E então na página CSHTML:

 @Html.IncludeVersionedJs("/MyJavascriptFile.js")

No HTML renderizado, isso aparece como:

 <script type='text/javascript' src='/MyJavascriptFile.js?20111129120000'></script>
Adam Tegen
fonte
1
isso é ótimo para mvc, gostaria de saber se o framework mvc 5 mais recente resolve esse problema? A abordagem que o empacotamento usa com o caractere curinga - {version} também é uma maneira de resolver este problema, no entanto, requer que os arquivos sejam renomeados após cada nova compilação ...
kiev
Estou usando o básico do seu exemplo MVC em um site de formulários da web e está funcionando muito bem, então obrigado por compartilhar!
Bryan
Deve haver algum motivo para se preocupar em exibir o carimbo de data / hora da última modificação para arquivos de recursos? Se um arquivo que está sendo usado tinha um carimbo de data / hora alguns anos atrás, poderia ser uma informação que uma empresa não deseja tornar pública para seus usuários?
Bryan
É a forma padrão, a maioria dos aplicativos segue. Mas esse registro de data e hora deve mudar apenas quando você implanta ou constrói seu aplicativo. Caso contrário, sempre que o usuário atualizar a página ou alternar para outras páginas em seu aplicativo. O navegador fará o download de todas as folhas de estilo e javascript novamente, o que não é bom
Tarun
2
Qual é o impacto no desempenho da página? Quanto atraso isso pode causar para carregar a página?
Durgesh Sonawane
28

Sua solução funciona. Na verdade, é bastante popular.

Até o Stack Overflow usa um método semelhante:

<link rel="stylesheet" href="http://sstatic.net/so/all.css?v=6184"> 

Onde v=6184está provavelmente o número de revisão do SVN.

Daniel Vassallo
fonte
Essa seria uma abordagem muito mais exigente do que a descrita na resposta aceita. Verificar a versão SVN do arquivo sempre que uma página é exibida é uma sobrecarga de desempenho, especialmente porque o número de usuários aumenta com o tempo.
Neolisk
4
Você pode obter o número da revisão durante a compilação, gravá-lo em um arquivo (por exemplo, arquivo .cs parcial), incluir esse arquivo em seu projeto, então você não precisa lê-lo de svn em tempo de execução. Usei essa abordagem com msbuild para colocar números de revisão em meus arquivos AssemblyInfo.cs de svn.
Ramazan Binarbasi
2
Usar um número de versão / revisão global tem pelo menos uma desvantagem: publicar uma atualização de site invalida os caches do navegador para todos os arquivos .js e .css, não apenas os que foram alterados. Isso provavelmente não importa na maioria dos aplicativos, mas menciono isso para ser completo.
Adam Tegen de
Se você atualizar a versão de seus arquivos assemblyinfo.cs automaticamente durante uma implantação ou compilação, a versão secundária pode ser usada para esse número.
kristianp
28

No ASP.NET Core (MVC 6), isso funciona imediatamente por meio do asp-append-versionassistente de tag:

<script src="scripts/myjavascript.js" asp-append-version="true"></script>
<link href="styles/mystyle.css rel="stylesheet" asp-append-version="true" />
metalheart
fonte
1
Obrigado por nos informar! Eu não sabia disso antes!
Federico Navarrete
18

A ASP.NET MVC cuidará disso para você se você usar pacotes para seu JS / CSS. Ele anexará automaticamente um número de versão na forma de um GUID aos seus pacotes e apenas atualizará esse GUID quando o pacote for atualizado (também conhecido como qualquer um dos arquivos de origem tem alterações).

Isso também ajuda se você tiver uma tonelada de arquivos JS / CSS, pois pode melhorar muito o tempo de carregamento do conteúdo!

Veja aqui

jonesy827
fonte
Você quer dizer que se usarmos pacotes em um aplicativo MVC, não há necessidade de nenhum dos métodos na resposta postada aqui? Nesse caso, o agrupamento é realmente muito mais importante do que eu já pensei. Você poderia nos esclarecer sobre esse assunto? Obrigado.
Jack
1
Sim, exatamente. Contanto que seus scripts estejam incluídos em um pacote, ele gerará um número de versão automaticamente para cada pacote quando alterações forem detectadas em qualquer um dos arquivos de origem do pacote.
jonesy827
E não se esqueça de que você ainda tem dores de cabeça como desenvolvedor. O empacotamento do ASP.NET não ajuda em nada durante a depuração e o desenvolvimento.
it3xl
12

Há uma maneira integrada no asp.net para isso: agrupamento . Apenas use. Cada nova versão terá o sufixo exclusivo "? V = XXXXXXX". No modo de depuração, o agrupamento está desativado, para ativar a configuração do make em web.config:

<system.web>
    <compilation debug="false" />
</system.web>

Ou adicione ao método RegisterBundles (bundleCollection bundles):

BundleTable.EnableOptimizations = true;

Por exemplo:

BundleConfig.cs:

bundles.Add(new ScriptBundle("~/Scripts/myjavascript.js")
                .Include("~/Scripts/myjavascript.js"));

bundles.Add(new StyleBundle("~/Content/mystyle.css")
                .Include("~/Content/mystyle.css"));

_Layout.cshtml:

@Scripts.Render("~/Scripts/myjavascript.js")
@Styles.Render("~/Content/mystyle.css")
Alex Tkachuk
fonte
Mas isso só funcionará em ambientes de lançamento ou produção. E quanto ao desenvolvimento quando o modo de depuração está ativado? O pacote ainda corrige esse problema?
VAAA de
Sim, bundlind não facilita a vida dos desenvolvedores. Você deve pressionar Ctrl-F5 após cada alteração de script. E se você tiver molduras, será ainda mais engraçado.
it3xl
6

Há uma resposta mais simples para isso do que a resposta dada pelo op na pergunta (a abordagem é a mesma):

Defina a chave no web.config:

<add key="VersionNumber" value="06032014"/>

Faça a chamada para appsettings diretamente da página aspx:

<link href="styles/navigation.css?v=<%=ConfigurationManager.AppSettings["VersionNumber"]%>" rel="stylesheet" type="text/css" />
4 revs
fonte
Eu gosto disso, mas estou preocupado porque essa solução tem tão poucos votos ...
SimplyInk
@SimplyInk Não sei, mas existem 20 respostas diferentes, então isso pode ter algo a ver com isso. Se funcionar e você gostar, sinta-se à vontade para votar a favor.
JackArbiter
4

Baseado na resposta de Adam Tegan , modificada para uso em um aplicativo de formulários da web.

No código da classe .cs:

public static class FileUtility
{
    public static string SetJsVersion(HttpContext context, string filename) {
        string version = GetJsFileVersion(context, filename);
        return filename + version;
    }

    private static string GetJsFileVersion(HttpContext context, string filename)
    {
        if (context.Cache[filename] == null)
        {
            string filePhysicalPath = context.Server.MapPath(filename);

            string version = "?v=" + GetFileLastModifiedDateTime(context, filePhysicalPath, "yyyyMMddhhmmss");

            return version;
        }
        else
        {
            return string.Empty;
        }
    }

    public static string GetFileLastModifiedDateTime(HttpContext context, string filePath, string dateFormat)
    {
        return new System.IO.FileInfo(filePath).LastWriteTime.ToString(dateFormat);
    }
}

Na marcação aspx:

<script type="text/javascript" src='<%= FileUtility.SetJsVersion(Context,"/js/exampleJavaScriptFile.js") %>'></script>

E no HTML renderizado, ele aparece como

<script type="text/javascript" src='/js/exampleJavaScriptFile.js?v=20150402021544'></script>
Bryan
fonte
2
Ei! Seu exemplo está funcionando, mas você deve remover as referências de cache ou corrigir o código para usar o cache, pois pode ser confuso o motivo pelo qual você o está usando. Para usar o cache, você deve adicionar a versão do arquivo ao cache usando o método context.Cache.Add no caso context.Cache [nome do arquivo] == null. Se context.Cache [nome do arquivo]! = Null então você deve retornar o valor do cache (context.Cache [nome do arquivo])
Flavia Obreja
1
Flavia, acho que sua explicação faz sentido, e acho que é uma implementação mais simples e eficiente. Obrigado por postar os comentários úteis e feedback.
Bryan
4

Curiosamente, este mesmo site tem problemas com a abordagem que você descreve em relação a algumas configurações de proxy, embora deva ser à prova de falhas.

Verifique esta discussão do Meta Stack Overflow .

Portanto, à luz disso, pode fazer sentido não usar um parâmetro GET para atualizar, mas o nome do arquivo real:

href="/css/scriptname/versionNumber.css" 

embora isso seja mais trabalho a fazer, já que você terá que realmente criar o arquivo ou construir uma reescrita de URL para ele.

Pekka 웃
fonte
4

Eu queria um liner simples para tornar o caminho exclusivo para invadir o cache. Isso funcionou para mim:

<script src="scripts/main.js?bust_js_cache=<%=System.IO.File.GetLastWriteTime(Server.MapPath("scripts/main.js")).ToString("HH:mm:ss")%>" type="text/javascript"></script>

Se o arquivo foi modificado desde a última vez que foi carregado na página, o navegador puxará o arquivo atualizado.

Ele gera o last modifiedcarimbo do .jsarquivo e o coloca ali, em vez da versão à qual pode não ser fácil obter acesso.

<script src="scripts/main.js?bust_js_cache=10:18:38" type="text/javascript"></script>

Outra opção pode ser obter a soma de verificação do arquivo.

atirador
fonte
1
De longe a maneira mais fácil de fazer isso e provavelmente a menor sobrecarga.
Tony Hinkle
1
Solução perfeita. Também testei o Chrome 70, o Firefox 63 e o IE 11 para ter certeza de que o cache estava realmente funcionando. Isto é. Isso apenas interrompe o armazenamento em cache em novas versões do arquivo, pelo menos nas versões mais recentes dos navegadores. Eu ouvi menção em outro lugar que alguns navegadores recarregam todos os arquivos com uma string de consulta (?). Talvez esse fosse o caso ou talvez ainda seja verdade com o Safari e o Opera. DK.
Brad Mathews
3

Aqui está uma abordagem que funciona com ASP.NET 5 / MVC 6 / vNext .

Etapa 1: Crie uma classe para retornar a hora da última gravação do arquivo, semelhante a outras respostas neste tópico. Observe que isso requer injeção de dependência ASP.NET 5 (ou outra).

public class FileVersionService
{
    private IHostingEnvironment _hostingEnvironment;
    public FileVersionService(IHostingEnvironment hostingEnvironment)
    {
        _hostingEnvironment = hostingEnvironment;
    }

    public string GetFileVersion(string filename)
    {
       var path = string.Format("{0}{1}", _hostingEnvironment.WebRootPath, filename);
       var fileInfo = new FileInfo(path);
       var version = fileInfo.LastWriteTimeUtc.ToString("yyyyMMddhhmmssfff");
       return version;
     }
}

Etapa 2: Registre o serviço a ser injetado dentro startup.cs :

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddScoped<FileVersionService>();
    ...
}

Etapa 3: então, no ASP.NET 5, é possível injetar o serviço diretamente em uma visualização de layout, como _Layout.cshtml, como este:

@inject Namespace.Here.FileVersionService fileVersionService
<!DOCTYPE html>
<html lang="en" class="@ViewBag.HtmlClass">
<head>
    ...
    <link href="/css/[email protected]("\\css\\styles.css")" rel="stylesheet" />
    ...
</head>
<body>
    ...
</body>

Existem alguns toques finais que podem ser feitos para combinar melhor os caminhos físicos e lidar com o nome do arquivo em um estilo mais consistente com a sintaxe, mas este é um ponto de partida. Espero que ajude as pessoas a migrar para o ASP.NET 5.

Ender2050
fonte
este comportamento é realmente suportado fora da caixa, veja minha resposta
metalheart
3

Empreguei uma técnica ligeiramente diferente no meu site aspnet MVC 4:

_ViewStart.cshtml:

@using System.Web.Caching
@using System.Web.Hosting
@{
    Layout = "~/Views/Shared/_Layout.cshtml";
    PageData.Add("scriptFormat", string.Format("<script src=\"{{0}}?_={0}\"></script>", GetDeployTicks()));
}

@functions
{

    private static string GetDeployTicks()
    {
        const string cacheKey = "DeployTicks";
        var returnValue = HttpRuntime.Cache[cacheKey] as string;
        if (null == returnValue)
        {
            var absolute = HostingEnvironment.MapPath("~/Web.config");
            returnValue = File.GetLastWriteTime(absolute).Ticks.ToString();
            HttpRuntime.Cache.Insert(cacheKey, returnValue, new CacheDependency(absolute));
        }
        return returnValue;
    }
}

Em seguida, nas visualizações reais:

 @Scripts.RenderFormat(PageData["scriptFormat"], "~/Scripts/Search/javascriptFile.min.js")
Anthony Wolfe
fonte
3

<?php $rand_no = rand(10000000, 99999999)?> <script src="scripts/myjavascript.js?v=<?=$rand_no"></script>

Isso funciona para mim em todos os navegadores. Aqui eu usei o PHP para gerar um número aleatório. Você pode usar sua própria linguagem do lado do servidor.

Mukesh Rai
fonte
Boa resposta, mas ASP MVC pode ser um pouco problemático se você não considerar o que Adam explicou porque eu tentei e a pasta Bundle não o reconhece se você trabalha com MVC 5. Mas obrigado pela sugestão!
Federico Navarrete
2

A partir da resposta acima , modifiquei um pouco o código para fazer o auxiliar trabalhar com arquivos CSS também e adicionar uma versão toda vez que você fizer alguma alteração nos arquivos e não apenas quando fizer a construção

public static class HtmlHelperExtensions
{
    public static MvcHtmlString IncludeVersionedJs(this HtmlHelper helper, string filename)
    {
        string version = GetVersion(helper, filename);
        return MvcHtmlString.Create("<script type='text/javascript' src='" + filename + version + "'></script>");
    }

    public static MvcHtmlString IncludeVersionedCss(this HtmlHelper helper, string filename)
    {
        string version = GetVersion(helper, filename);
        return MvcHtmlString.Create("<link href='" + filename + version + "' type ='text/css' rel='stylesheet'/>");
    }

    private static string GetVersion(this HtmlHelper helper, string filename)
    {
        var context = helper.ViewContext.RequestContext.HttpContext;
        var physicalPath = context.Server.MapPath(filename);
        var version = "?v=" +
        new System.IO.FileInfo(physicalPath).LastWriteTime
        .ToString("yyyyMMddHHmmss");
        context.Cache.Add(physicalPath, version, null,
          DateTime.Now.AddMinutes(1), TimeSpan.Zero,
          CacheItemPriority.Normal, null);

        if (context.Cache[filename] == null)
        {
            context.Cache[filename] = version;
            return version;
        }
        else
        {
            if (version != context.Cache[filename].ToString())
            {
                context.Cache[filename] = version;
                return version;
            }
            return context.Cache[filename] as string;
        }
    }
}
Sergi Mulà
fonte
1

Obtenha a hora de modificação do arquivo, conforme mostrado abaixo

private static string GetLastWriteTimeForFile(string pathVal)
    {
        return System.IO.File.GetLastWriteTime(HostingEnvironment.MapPath(pathVal)).ToFileTime().ToString();
    }

Anexe isso com input como querystring

public static string AppendDateInFile(string pathVal)
    {
        var patheWithDate = new StringBuilder(pathVal);
        patheWithDate.AppendFormat("{0}x={1}",
                               pathVal.IndexOf('?') >= 0 ? '&' : '?',
                               GetLastWriteTimeForFile(pathVal));
        return patheWithDate.ToString();
    }

Chame isso de marcação.

Abordagem MVC Extension Helper

Adicionar um método de extensão

namespace TNS.Portal.Helpers
{
    public static class ScriptExtensions
    {
        public static HtmlString QueryStringScript<T>(this HtmlHelper<T> html, string path)
        {
            var file = html.ViewContext.HttpContext.Server.MapPath(path);
            DateTime lastModified = File.GetLastWriteTime(file);
            TagBuilder builder = new TagBuilder("script");
            builder.Attributes["src"] = path + "?modified=" + lastModified.ToString("yyyyMMddhhmmss");
            return new HtmlString(builder.ToString());
        }

       public static HtmlString QueryStringStylesheet<T>(this HtmlHelper<T> html, string path)
       {
        var file = html.ViewContext.HttpContext.Server.MapPath(path);
        DateTime lastModified = File.GetLastWriteTime(file);
        TagBuilder builder = new TagBuilder("link");
        builder.Attributes["href"] = path + "?modified=" + lastModified.ToString("yyyyMMddhhmmss");
        builder.Attributes["rel"] = "stylesheet";
        return new HtmlString(builder.ToString());
      }

    }
}

Adicione este namespace em web.config

<system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization"/>
        <add namespace="System.Web.Routing" />
        <add namespace="TNS.Portal" />
        <add namespace="TNS.Portal.Helpers" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>

Use-o para ver como

@Html.QueryStringScript("/Scripts/NPIAjaxCalls.js")
@Html.QueryStringStylesheet("/Content/StyledRadio.css")
Lijo
fonte
1

Sugestões anteriores simplificadas e fornecimento de código para desenvolvedores de formulários da Web em .NET.

Isso aceitará urls relativos ("~ /") e absolutos no caminho do arquivo para o recurso.

Coloque em um arquivo de classe de extensões estáticas, o seguinte:

public static string VersionedContent(this HttpContext httpContext, string virtualFilePath)
{
    var physicalFilePath = httpContext.Server.MapPath(virtualFilePath);
    if (httpContext.Cache[physicalFilePath] == null)
    {
        httpContext.Cache[physicalFilePath] = ((Page)httpContext.CurrentHandler).ResolveUrl(virtualFilePath) + (virtualFilePath.Contains("?") ? "&" : "?") + "v=" + File.GetLastWriteTime(physicalFilePath).ToString("yyyyMMddHHmmss");
    }
    return (string)httpContext.Cache[physicalFilePath];
}

E então chame-o em sua página mestra como tal:

<link type="text/css" rel="stylesheet" href="<%= Context.VersionedContent("~/styles/mystyle.css") %>" />
<script type="text/javascript" src="<%= Context.VersionedContent("~/scripts/myjavascript.js") %>"></script>
Jason Ellingson
fonte
Boa abordagem também!
Federico Navarrete
0

Com base na resposta acima, escrevi uma pequena classe de extensão para trabalhar com arquivos CSS e JS:

public static class TimestampedContentExtensions
{
    public static string VersionedContent(this UrlHelper helper, string contentPath)
    {
        var context = helper.RequestContext.HttpContext;

        if (context.Cache[contentPath] == null)
        {
            var physicalPath = context.Server.MapPath(contentPath);
            var version = @"v=" + new FileInfo(physicalPath).LastWriteTime.ToString(@"yyyyMMddHHmmss");

            var translatedContentPath = helper.Content(contentPath);

            var versionedContentPath =
                contentPath.Contains(@"?")
                    ? translatedContentPath + @"&" + version
                    : translatedContentPath + @"?" + version;

            context.Cache.Add(physicalPath, version, null, DateTime.Now.AddMinutes(1), TimeSpan.Zero,
                CacheItemPriority.Normal, null);

            context.Cache[contentPath] = versionedContentPath;
            return versionedContentPath;
        }
        else
        {
            return context.Cache[contentPath] as string;
        }
    }
}

Em vez de escrever algo como:

<link href="@Url.Content(@"~/Content/bootstrap.min.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content(@"~/Scripts/bootstrap.min.js")"></script>

Agora você pode escrever:

<link href="@Url.VersionedContent(@"~/Content/bootstrap.min.css")" rel="stylesheet" type="text/css" />
<script src="@Url.VersionedContent(@"~/Scripts/bootstrap.min.js")"></script>

Ou seja, simplesmente substitua Url.ContentporUrl.VersionedContent .

Os URLs gerados são semelhantes a:

<link href="/Content/bootstrap.min.css?v=20151104105858" rel="stylesheet" type="text/css" />
<script src="/Scripts/bootstrap.min.js?v=20151029213517"></script>

Se você usar a classe de extensão, você pode querer adicionar tratamento de erros caso a MapPathchamada não funcione, já que contentPathnão é um arquivo físico.

Uwe Keim
fonte
0

Eu uso uma maneira semelhante para fazer o mesmo que você está fazendo, sem modificar cada página. Adicionado um evento PreRender é um arquivo mestre. Ele mantém minha lógica em um lugar e aplicável a arquivos js e css.

protected void Page_PreRender(object sender, EventArgs e)
    {
        HtmlLink link = null;
        LiteralControl script = null;


        foreach (Control c in Header.Controls)
        {
            //StyleSheet add version
            if (c is HtmlLink)
            {
                link = c as HtmlLink;


                if (link.Href.EndsWith(".css", StringComparison.InvariantCultureIgnoreCase))
                {
                    link.Href += string.Format("?v={0}", ConfigurationManager.AppSettings["agVersion"]);
                }

            }

            //Js add version
            if (c is LiteralControl)
            {
                script = c as LiteralControl;

                if (script.Text.Contains(".js"))
                {
                    var foundIndexes = new List<int>();


                    for (int i = script.Text.IndexOf(".js\""); i > -1; i = script.Text.IndexOf(".js\"", i + 1))
                    {

                        foundIndexes.Add(i);
                    }

                    for (int i = foundIndexes.Count - 1; i >= 0; i--)
                    {

                        script.Text = script.Text.Insert(foundIndexes[i] + 3, string.Format("?v={0}", ConfigurationManager.AppSettings["agVersion"]));
                    }
                }

            }

        }
    }
Jay
fonte
0

Você pode substituir a propriedade DefaultTagFormat de Scripts ou Estilos.

Scripts.DefaultTagFormat = @"<script src=""{0}?v=" + ConfigurationManager.AppSettings["pubversion"] + @"""></script>";
Styles.DefaultTagFormat = @"<link href=""{0}?v=" + ConfigurationManager.AppSettings["pubversion"] + @""" rel=""stylesheet""/>";
Fénix
fonte
0

Para resolver esse problema em meu aplicativo ASP.Net Ajax, criei uma extensão e chamei a página mestra.

Para mais detalhes, você pode acessar o link .

Kasim Husaini
fonte
0

Maneira fácil e inteligente de implementar o controle de versão de css no aplicativo .net pelo conceito abaixo ... sem necessidade de escrever código de back-end.

<link href="<%="../../App_Themes/Base/css/main.css?v="+ DateTime.Now.ToString("yyyyMMddhhmmss") +""%>" rel="stylesheet" />
SantoshK
fonte
isso forçará o download em cada renderização de página, mesmo que os arquivos não tenham sido alterados.
Thanasis Ioannidis
@ThanasisIoannidis Pode ser usado onde os arquivos são alterados regularmente. outra opção é adicionar a chave appVersion em web.config e usar com o nome dos arquivos .. mas você precisa atualizar quando liberar o aplicativo para prod.
SantoshK
-1

O principal problema em fazer isso dessa maneira é principalmente que você precisará se lembrar de atualizar o número da versão no código toda vez que fizer qualquer alteração nos arquivos css ou js.

Uma maneira possivelmente melhor de fazer isso é definir um parâmetro exclusivo garantido com cada um dos seus arquivos css ou js, assim:

<script src="scripts/myjavascript.js?_=<%=DateTime.Now.Ticks%>" type="text/javascript"></script>
<link href="styles/mystyle.css?_=<%=DateTime.Now.Ticks%>" rel="stylesheet" type="text/css" />

Isso força os arquivos a serem solicitados do servidor todas as vezes, o que também significa que seu site não terá o mesmo desempenho no carregamento da página, pois esses arquivos nunca serão armazenados em cache e usarão largura de banda desnecessária todas as vezes.

Essencialmente, se você se lembrar de atualizar o número da versão toda vez que uma alteração for feita, você poderá fazer o que está fazendo.

Tim S. Van Haren
fonte
9
e usa grandes quantidades de largura de banda também.
Darren Kopp
2
Certo, você não quer uma nova versão do JS a cada carregamento de página ... você só quer que o navegador procure uma nova versão cada vez que você realmente tiver uma versão atualizada.
kingdango
Isso é perfeitamente aceitável para uma solução temporária em um arquivo css de 50 KB durante o desenvolvimento. +1
Colbs de
-2

Para páginas ASP.NET, estou usando o seguinte

ANTES

<script src="/Scripts/pages/common.js" type="text/javascript"></script>

DEPOIS (forçar recarga)

 <script src="/Scripts/pages/common.js?ver<%=DateTime.Now.Ticks.ToString()%>" type="text/javascript"></script>

Adicionar o DateTime.Now.Ticks funciona muito bem.

Ravi Ram
fonte
sim, o problema é com a largura de banda - como nos comentários acima stackoverflow.com/a/2185918/59508
kiev