programing

브라우저가 asp.net 응용 프로그램에서 최신 js 및 css 파일을 가져오도록 합니다.

padding 2023. 5. 18. 20:47
반응형

브라우저가 asp.net 응용 프로그램에서 최신 js 및 css 파일을 가져오도록 합니다.

일부 브라우저는 js 및 css 파일을 캐시하여 강제로 새로 고치지 않으면 새로 고치지 못합니다.가장 쉬운 방법은 무엇입니까?

저는 효과가 있을 것 같은 이 솔루션을 구현했습니다.

페이지에서 버전 변수 선언

  public string version { get; set; }

web.config 키에서 버전 번호 가져오기

 version = ConfigurationManager.AppSettings["versionNumber"];

당신의 aspx 페이지에서 Javascript와 스타일시트에 그렇게 전화를 겁니다.

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

따라서 web.config에서 버전 = 1.1을 1.0에서 설정하면 브라우저가 최신 파일을 다운로드하여 사용자와 사용자의 불만을 덜어줄 것입니다.

더 잘 작동하는 다른 솔루션이 있습니까? 아니면 웹 사이트에 예기치 않은 문제를 일으킬 수 있습니까?

마지막으로 수정된 타임스탬프를 쿼리 매개 변수로 스크립트에 적용하여 이 문제를 해결했습니다.

저는 이것을 확장 방법으로 했고, 제 CSHTML 파일에 사용했습니다.참고: 이 구현은 디스크를 너무 많이 스레싱하지 않도록 타임스탬프를 1분 동안 캐시합니다.

확장 방법은 다음과 같습니다.

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;
        }
    }
}

그런 다음 CSHTML 페이지에서 다음 작업을 수행합니다.

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

렌더링된 HTML에서는 다음과 같이 표시됩니다.

 <script type='text/javascript' src='/MyJavascriptFile.js?20111129120000'></script>

ASP.NET Core(MVC 6)에서 이 기능은 다음을 통해 즉시 작동합니다.asp-append-version태그 도우미:

<script src="scripts/myjavascript.js" asp-append-version="true"></script>
<link href="styles/mystyle.css rel="stylesheet" asp-append-version="true" />

솔루션이 작동합니다.사실 그것은 꽤 인기가 있습니다.

스택 오버플로도 유사한 방법을 사용합니다.

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

어디에v=6184SVN 리비전 번호일 것입니다.

JS/CSS에 번들을 사용하는 경우 ASP.NET MVC가 이 작업을 대신 처리합니다.번들에 GUID 형식의 버전 번호가 자동으로 추가되고 번들이 업데이트될 때만 이 GUID가 업데이트됩니다(소스 파일에 변경 사항이 있음).

이는 콘텐츠 로드 시간을 크게 향상시킬 수 있기 때문에 JS/CSS 파일이 많은 경우에도 도움이 됩니다!

여기 참조

asp.net 에는 번들링이라는 기본 제공 방법이 있습니다.그냥 쓰세요.새 버전마다 고유 접미사 "?v=XXXXXXX"가 붙습니다.디버깅 모드에서는 web.config의 make 설정을 켜기 위해 번들링이 꺼집니다.

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

또는 RegisterBundle(BundleCollection 번들) 메서드에 다음을 추가합니다.

BundleTable.EnableOptimizations = true;

예:

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")

캐시를 부수기 위해 경로를 고유하게 만드는 간단한 라이너가 필요했습니다.이것은 저에게 효과가 있었습니다.

<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>

파일이 페이지에 마지막으로 로드된 이후로 수정된 경우 브라우저는 업데이트된 파일을 풀합니다.

을 생성합니다.last modified을 찍다.js파일을 저장하고 접근이 쉽지 않을 수 있는 버전 대신에 파일을 저장합니다.

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

다른 옵션은 파일의 체크섬을 가져오는 것일 수 있습니다.

이에 대한 답은 질문의 op가 제시한 답보다 더 간단합니다(접근법은 동일합니다).

web.config에서 키를 정의합니다.

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

aspx 페이지에서 app 설정으로 직접 전화 걸기:

<link href="styles/navigation.css?v=<%=ConfigurationManager.AppSettings["VersionNumber"]%>" rel="stylesheet" type="text/css" />

Adam Tegan의 답변을 기반으로 웹 양식 응용 프로그램에서 사용하도록 수정되었습니다.

.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);
    }
}

aspx 마크업에서:

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

그리고 렌더링된 HTML에서 다음과 같이 나타납니다.

<script type="text/javascript" src='/js/exampleJavaScriptFile.js?v=20150402021544'></script>

다음은 ASP.NET 5 / MVC 6 / vNext에서 작동하는 접근 방식입니다.

1단계: 이 스레드의 다른 답변과 유사하게 파일의 마지막 쓰기 시간을 반환하는 클래스를 만듭니다.이 경우 ASP.NET 5(또는 기타) 종속성 주입이 필요합니다.

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;
     }
}

2단계: startup.cs 에 주입할 서비스를 등록합니다.

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

3단계: 그런 다음 ASP.NET 5에서 다음과 같이 _Layout.cshtml과 같은 레이아웃 보기에 서비스를 직접 주입할 수 있습니다.

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

물리적 경로를 더 잘 결합하고 구문과 더 일치하는 스타일로 파일 이름을 처리하기 위해 몇 가지 마무리 작업을 수행할 수 있지만, 이것이 시작점입니다.ASP.NET 5로 이동하는 사람들에게 도움이 되길 바랍니다.

흥미롭게도 이 사이트는 페일 세이프여야 하지만 일부 프록시 설정과 관련하여 설명한 접근 방식에 문제가 있습니다.

이 메타 스택 오버플로 토론을 확인하십시오.

따라서 이를 고려할 때 GET 매개 변수를 사용하여 업데이트하지 않고 실제 파일 이름을 사용하는 것이 합리적일 수 있습니다.

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

파일을 실제로 생성하거나 URL을 다시 작성해야 하기 때문에 이 작업이 더 많은 작업임에도 불구하고,

저는 제 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;
    }
}

그러면 실제 보기에서:

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

의 답변에서 시작하여 저는 도우미가 CSS 파일에서도 작동하도록 코드를 약간 수정했고 빌드를 할 때뿐만 아니라 파일에서 약간의 변경을 할 때마다 버전을 추가했습니다.

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;
        }
    }
}

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

이것은 모든 브라우저에서 작동합니다.여기서 저는 PHP를 사용하여 임의의 no를 생성했습니다.자신의 서버 사이드 언어를 사용할 수 있습니다.`

아래 표시된 대로 파일 수정 시간 가져오기

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

입력을 쿼리 문자열로 추가합니다.

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

마크업에서 호출합니다.

MVC 확장 도우미 접근법

확장 메서드 추가

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());
      }

    }
}

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>

보기에서 다음과 같이 사용

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

.NET Web Forms 개발자를 위한 간단한 사전 제안 및 코드 제공.

리소스에 대한 파일 경로의 상대 URL("~/")과 절대 URL을 모두 허용합니다.

다음과 같은 정적 확장명 클래스 파일을 넣습니다.

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];
}

그런 다음 마스터 페이지에서 다음과 같이 호출합니다.

<link type="text/css" rel="stylesheet" href="<%= Context.VersionedContent("~/styles/mystyle.css") %>" />
<script type="text/javascript" src="<%= Context.VersionedContent("~/scripts/myjavascript.js") %>"></script>

이런 식으로 하는 것의 주된 문제는 주로 당신이 당신의 css 또는 js 파일을 변경할 때마다 당신의 코드에서 당신의 버전 번호를 업데이트하는 것을 기억해야 한다는 것입니다.

더 나은 방법은 다음과 같이 각 CSS 또는 Js 파일에 보장된 고유 매개 변수를 설정하는 것입니다.

<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" />

이렇게 하면 매번 서버에서 파일을 요청해야 합니다. 즉, 사이트는 페이지 로드 시 캐시되지 않고 매번 불필요한 대역폭을 사용하기 때문에 성능이 저하됩니다.

기본적으로 변경할 때마다 버전 번호를 업데이트하는 것을 기억할 수 있다면 변경 방법에서 벗어날 수 있습니다.

의 답변을 바탕으로 CSS와 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;
        }
    }
}

다음과 같은 것을 쓰는 대신:

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

이제 다음을 쓸 수 있습니다.

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

즉, 간단히 교체할 수 있습니다.Url.Content와 함께Url.VersionedContent.

생성된 URL은 다음과 같습니다.

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

할 수 .MapPath안 요, 통가작않습다니지하동화▁since.contentPath실제 파일이 아닙니다.

저는 각 페이지를 수정하지 않고 당신이 하고 있는 것과 비슷한 방법을 사용합니다.PreRender 이벤트가 마스터 파일로 추가되었습니다.그것은 내 논리를 한 곳에 유지하고 js와 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"]));
                    }
                }

            }

        }
    }

스크립트 또는 스타일의 DefaultTagFormat 속성을 재정의할 수 있습니다.

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

ASP.Net Ajax 애플리케이션에서 이 문제를 해결하기 위해 내선번호를 생성한 다음 마스터 페이지를 호출했습니다.

자세한 내용은 링크를 통해 확인하실 수 있습니다.

아래의 개념에 의해 .net 응용 프로그램에서 CSS 버전 관리를 구현하는 쉽고 똑똑한 방법.백엔드 코드를 쓸 필요가 없습니다.

<link href="<%="../../App_Themes/Base/css/main.css?v="+ DateTime.Now.ToString("yyyyMMddhhmmss") +""%>" rel="stylesheet" />

ASP.NET 페이지의 경우 다음을 사용합니다.

전에

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

AFTER(강제 재로드)

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

날짜 시간을 추가하는 중입니다.이제, 틱은 아주 잘 작동합니다.

그냥 이것을 내부 시스템에 넣으십시오.web.config의 웹 서버

<caching enabled="true" enableKernelCache="true">
      <profiles>
        <add extension=".html" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange"/>
        <add extension=".css" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange"/>
        <add extension=".js" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange"/>
      </profiles>
    </caching>

언급URL : https://stackoverflow.com/questions/2185872/force-browsers-to-get-latest-js-and-css-files-in-asp-net-application

반응형