บังคับให้เบราว์เซอร์รับไฟล์ js และ css ล่าสุดในแอปพลิเคชัน asp.net


104

เบราว์เซอร์บางตัวแคชไฟล์ js และ css ไม่สามารถรีเฟรชได้เว้นแต่คุณจะบังคับให้ทำ วิธีใดง่ายที่สุด

ฉันเพิ่งใช้โซลูชันนี้ซึ่งดูเหมือนว่าจะได้ผล

ประกาศตัวแปรเวอร์ชันบนเพจของคุณ

  public string version { get; set; }

รับหมายเลขเวอร์ชันจากคีย์ web.config

 version = ConfigurationManager.AppSettings["versionNumber"];

ในหน้า aspx ของคุณให้เรียกใช้จาวาสคริปต์และสไตล์ชีทเช่นนั้น

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

ดังนั้นหากคุณตั้งค่าเวอร์ชัน = 1.1 จาก 1.0 ใน web.config เบราว์เซอร์ของคุณจะดาวน์โหลดไฟล์ล่าสุดซึ่งหวังว่าจะช่วยให้คุณและผู้ใช้ของคุณไม่ต้องหงุดหงิด

มีวิธีแก้ไขอื่นที่ทำงานได้ดีกว่าหรือไม่หรือจะทำให้เกิดปัญหาที่ไม่คาดคิดสำหรับเว็บไซต์หรือไม่


คำถามที่น่าสนใจฉันมีปัญหาเดียวกันเมื่อเร็ว ๆ นี้ แต่เป็นเพียงปัญหาระหว่างการทดสอบการพัฒนา ไม่ได้สนใจมันมากนักเนื่องจากเราไม่ได้ตั้งใจที่จะเปลี่ยนไฟล์เหล่านั้นหลังจากเปิดตัว ชอบที่จะรู้วิธีแก้ปัญหาสำหรับการอ้างอิงในอนาคต!
Brett Allen

ปัญหาเดียวที่ฉันเห็นคือการเปลี่ยนแปลงใน web.config จะเรียกการรีสตาร์ทแอปพลิเคชันในพื้นหลัง: msdn.microsoft.com/en-us/library/aa478432.aspx
monty

ขอบคุณสำหรับคำถาม สิ่งนี้ช่วยฉันในการแก้ปัญหาใหญ่
Reddy

คำตอบ:


77

ฉันแก้ไขปัญหานี้โดยยึดการประทับเวลาที่แก้ไขล่าสุดเป็นพารามิเตอร์การสืบค้นไปยังสคริปต์

ฉันทำสิ่งนี้ด้วยวิธีการขยายและใช้ในไฟล์ 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>

1
นี่เป็นสิ่งที่ยอดเยี่ยมสำหรับ mvc ฉันสงสัยว่าเฟรมเวิร์ก mvc 5 ล่าสุดจัดการปัญหานี้ได้หรือไม่ วิธีการที่บันเดิลใช้กับ - สัญลักษณ์ตัวแทน {version} ก็เป็นวิธีการแก้ปัญหานี้เช่นกัน แต่ต้องเปลี่ยนชื่อไฟล์หลังจากสร้างใหม่แต่ละครั้ง ...
kiev

ฉันใช้พื้นฐานของตัวอย่าง MVC ของคุณในเว็บไซต์เว็บฟอร์มและใช้งานได้ดีมากขอขอบคุณที่แบ่งปัน!
ไบรอัน

มีเหตุผลใดที่ต้องกังวลเกี่ยวกับการแสดงการประทับวันที่ / เวลาที่แก้ไขล่าสุดสำหรับไฟล์ทรัพยากรหรือไม่? หากไฟล์ที่ใช้มีการประทับวันที่ / เวลาเมื่อไม่กี่ปีที่ผ่านมาอาจเป็นข้อมูลที่ บริษัท อาจไม่ต้องการเปิดเผยต่อผู้ใช้ของตน
ไบรอัน

เป็นวิธีมาตรฐานโดยส่วนใหญ่ใช้งานตามนี้ แต่การประทับเวลานั้นควรเปลี่ยนเมื่อคุณปรับใช้หรือสร้างแอปพลิเคชันของคุณเท่านั้น มิฉะนั้นทุกครั้งที่ผู้ใช้รีเฟรชหน้าหรือเปลี่ยนไปยังหน้าอื่น ๆ ในแอปพลิเคชันของคุณ เบราว์เซอร์จะดาวน์โหลดสไตล์ชีทและจาวาสคริปต์ทั้งหมดของคุณอีกครั้งซึ่งไม่ดี
Tarun

2
ผลกระทบต่อประสิทธิภาพของเพจคืออะไร? การโหลดหน้าเว็บจะล่าช้ามากน้อยเพียงใด
Durgesh Sonawane

28

โซลูชันของคุณใช้ได้ผล เป็นที่นิยมมากในความเป็นจริง

แม้แต่ Stack Overflow ก็ใช้วิธีการที่คล้ายกัน:

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

v=6184หมายเลขการแก้ไข SVN อาจอยู่ที่ไหน


นี่จะเป็นวิธีการเก็บภาษีมากกว่าวิธีที่อธิบายไว้ในคำตอบที่ยอมรับ การตรวจสอบเวอร์ชัน SVN ของไฟล์ทุกครั้งที่มีการแสดงเพจถือเป็นค่าใช้จ่ายด้านประสิทธิภาพโดยเฉพาะอย่างยิ่งเมื่อจำนวนผู้ใช้เพิ่มขึ้นเมื่อเวลาผ่านไป
Neolisk

4
คุณสามารถรับหมายเลขการแก้ไขในระหว่างการสร้างเขียนลงในไฟล์ (เช่นไฟล์. cs บางส่วน) รวมไฟล์นั้นไว้ในโปรเจ็กต์ของคุณดังนั้นคุณไม่จำเป็นต้องอ่านจาก svn ที่รันไทม์ ฉันใช้วิธีนี้กับ msbuild เพื่อใส่หมายเลขการแก้ไขในไฟล์ AssemblyInfo.cs ของฉันจาก svn
Ramazan Binarbasi

2
การใช้เวอร์ชันสากล / หมายเลขการแก้ไขมีข้อเสียเปรียบอย่างน้อยหนึ่งประการ: การเผยแพร่การอัปเดตเว็บไซต์ทำให้แคชเบราว์เซอร์ไม่ถูกต้องสำหรับไฟล์. js และ. css ทั้งหมดไม่ใช่เฉพาะไฟล์ที่เปลี่ยนแปลง สิ่งนี้อาจไม่สำคัญในการใช้งานส่วนใหญ่ แต่ฉันพูดถึงมันเพื่อความสมบูรณ์
Adam Tegen

หากคุณอัปเดตเวอร์ชันของไฟล์ assemblyinfo.cs ของคุณโดยอัตโนมัติระหว่างการปรับใช้หรือบิลด์อาจใช้เวอร์ชันรองสำหรับหมายเลขนั้น
kristianp

28

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

1
ขอบคุณที่แจ้งให้เราทราบ! ไม่รู้มาก่อน!
Federico Navarrete

18

ASP.NET MVC จะจัดการสิ่งนี้ให้คุณหากคุณใช้บันเดิลสำหรับ JS / CSS ของคุณ โดยจะเพิ่มหมายเลขเวอร์ชันในรูปแบบของ GUID เข้ากับบันเดิลของคุณโดยอัตโนมัติและอัปเดต GUID นี้เมื่อมีการอัปเดตบันเดิลเท่านั้น (หรือที่เรียกว่าไฟล์ต้นฉบับใด ๆ มีการเปลี่ยนแปลง)

นอกจากนี้ยังช่วยหากคุณมีไฟล์ JS / CSS จำนวนมากเนื่องจากสามารถปรับปรุงเวลาในการโหลดเนื้อหาได้อย่างมาก!

ดูที่นี่


คุณหมายความว่าถ้าเราใช้บันเดิลในแอปพลิเคชัน MVC ไม่จำเป็นต้องมีวิธีการใด ๆ ในโพสต์คำตอบที่นี่? ถ้าเป็นเช่นนั้นการรวมกลุ่มมีความสำคัญมากกว่าที่ฉันเคยคิดไว้ คุณช่วยชี้แจงเราเกี่ยวกับปัญหานี้ได้ไหม ขอบคุณ.
แจ็ค

1
ใช่แน่นอน ตราบใดที่สคริปต์ของคุณรวมอยู่ในบันเดิลสคริปต์จะสร้างหมายเลขเวอร์ชันโดยอัตโนมัติสำหรับแต่ละบันเดิลเมื่อตรวจพบการเปลี่ยนแปลงในซอร์สไฟล์ใด ๆ ของบันเดิล
jonesy827

และอย่าลืมว่าคุณยังคงปวดหัวในฐานะนักพัฒนา การบันเดิล ASP.NET ไม่ช่วยอะไรในระหว่างการดีบักและการพัฒนา
it3xl

12

มีในตัววิธีการใน asp.net สำหรับการนี้: bundling เพียงแค่ใช้มัน เวอร์ชันใหม่แต่ละรายการจะมีส่วนต่อท้าย "? v = XXXXXXX" ที่ไม่ซ้ำกัน ในโหมดดีบักบันเดิลปิดอยู่สำหรับการเปิด make setting ใน web.config:

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

หรือเพิ่มในเมธอด RegisterBundles (บันเดิล 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")

แต่จะใช้ได้เฉพาะในสภาพแวดล้อมการเปิดตัวหรือการผลิตเท่านั้น แล้วการพัฒนาเมื่อเปิดโหมดดีบักล่ะ? บันเดิลยังแก้ปัญหานี้อยู่ไหม
VAAA

ใช่ Bundlind ไม่ได้ทำให้นักพัฒนาใช้ชีวิตง่ายขึ้น คุณต้องกด Ctrl-F5 หลังจากเปลี่ยนสคริปต์แต่ละครั้ง และถ้าคุณมีเฟรมก็จะยิ่งตลก
it3xl

7

มีคำตอบที่ง่ายกว่าคำตอบที่ได้รับจาก op ในคำถาม (แนวทางเดียวกัน):

กำหนดคีย์ใน web.config:

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

โทรไปยัง appsettings โดยตรงจากหน้า aspx:

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

ฉันชอบสิ่งนี้ แต่ฉันกังวลว่าทำไมโซลูชันนี้จึงมีคะแนนโหวตน้อยมาก ...
SimplyInk

@SimplyInk ฉันไม่รู้ แต่มี 20 คำตอบที่แตกต่างกันดังนั้นอาจมีบางอย่างเกี่ยวข้องกับมัน หากได้ผลและคุณชอบอย่าลังเลที่จะโหวตให้คะแนน
JackArbiter

4

ขึ้นอยู่กับ คำตอบของ 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>

2
เฮ้! ตัวอย่างของคุณใช้งานได้ แต่คุณควรลบการอ้างอิงแคชหรือแก้ไขโค้ดเพื่อใช้แคชเพราะอาจทำให้สับสนได้ว่าทำไมคุณถึงใช้มัน ในการใช้แคชคุณควรเพิ่มเวอร์ชันของไฟล์ลงในแคชโดยใช้ context.Cache.Add method ใน case context.Cache [filename] == null ถ้า context.Cache [filename]! = null คุณควรส่งคืนค่าแคช (context.Cache [ชื่อไฟล์])
Flavia Obreja

1
Flavia ฉันคิดว่าคำอธิบายของคุณมีเหตุผลและฉันคิดว่ามันเป็นการใช้งานที่ง่ายและมีประสิทธิภาพมากกว่า ขอบคุณสำหรับการโพสต์ความคิดเห็นและข้อเสนอแนะที่เป็นประโยชน์
ไบรอัน

4

ที่น่าสนใจคือไซต์นี้มีปัญหาเกี่ยวกับวิธีการที่คุณอธิบายเกี่ยวกับการตั้งค่าพร็อกซีบางอย่างแม้ว่าจะไม่ปลอดภัยก็ตาม

ตรวจสอบการสนทนาMeta Stack Overflowนี้

ดังนั้นในแง่นี้จึงไม่ควรใช้พารามิเตอร์ GET เพื่ออัปเดต แต่ชื่อไฟล์จริง:

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

แม้ว่าจะต้องทำมากกว่านี้เนื่องจากคุณจะต้องสร้างไฟล์จริงหรือสร้าง URL ที่เขียนใหม่


4

ฉันต้องการซับเส้นเดียวเพื่อทำให้เส้นทางไม่ซ้ำกันเพื่อปิดแคช สิ่งนี้ใช้ได้ผลสำหรับฉัน:

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

อีกทางเลือกหนึ่งคือการรับการตรวจสอบของไฟล์


1
วิธีที่ง่ายที่สุดในการทำเช่นนี้และอาจเป็นค่าโสหุ้ยต่ำสุด
Tony Hinkle

1
โซลูชั่นที่สมบูรณ์แบบ ฉันยังทดสอบ Chrome 70, Firefox 63 และ IE 11 เพื่อให้แน่ใจว่าการแคชใช้งานได้จริง มันคือ. นี่เป็นเพียงการแคชไฟล์เวอร์ชันใหม่อย่างน้อยที่สุดในเบราว์เซอร์เวอร์ชันล่าสุด ฉันเคยได้ยินพูดถึงที่อื่นว่าเบราว์เซอร์บางตัวโหลดซ้ำทุกไฟล์ด้วยสตริงคำค้นหา (?) อาจจะเป็นเช่นนั้นหรืออาจจะยังคงเป็นจริงกับ Safari และ Opera DK.
Brad Mathews

3

นี่คือวิธีการที่ทำงานร่วมกับ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


พฤติกรรมนี้ได้รับการสนับสนุนนอกกรอบดูคำตอบของฉัน
metalheart

3

ฉันได้ใช้เทคนิคที่แตกต่างกันเล็กน้อยในไซต์ 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")

3

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

สิ่งนี้ใช้ได้กับฉันในทุกเบราว์เซอร์ ที่นี่ฉันใช้ PHP เพื่อสร้างเลขสุ่ม คุณสามารถใช้ภาษาฝั่งเซิร์ฟเวอร์ของคุณเองได้


คำตอบที่ดี แต่ ASP MVC อาจเป็นปัญหาเล็กน้อยหากคุณไม่พิจารณาสิ่งที่ Adam อธิบายเพราะฉันลองแล้วและโฟลเดอร์ Bundle ไม่รู้จักหากคุณทำงานกับ MVC 5 แต่ขอบคุณสำหรับคำแนะนำ!
Federico Navarrete

2

เริ่มจากคำตอบข้างต้นฉันได้แก้ไขโค้ดเล็กน้อยเพื่อให้ตัวช่วยทำงานกับไฟล์ 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;
        }
    }
}

1

รับเวลาแก้ไขไฟล์ดังที่แสดงด้านล่าง

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 Extension Helper Approach

เพิ่มวิธีการขยาย

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

1

คำแนะนำก่อนหน้านี้ง่ายขึ้นและการให้โค้ดสำหรับนักพัฒนา. NET Web Forms

ซึ่งจะยอมรับทั้งแบบสัมพัทธ์ ("~ /") และ 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];
}

จากนั้นเรียกมันใน Master Page ของคุณดังนี้:

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

แนวทางที่ดีเช่นกัน!
Federico Navarrete

0

จากคำตอบข้างต้นฉันได้เขียนคลาสส่วนขยายขนาดเล็กเพื่อทำงานกับไฟล์ 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โทรไม่ทำงานเนื่องจากcontentPathไม่ใช่ไฟล์ทางกายภาพ


0

ฉันใช้วิธีที่คล้ายกันในการทำเช่นเดียวกับที่คุณทำโดยไม่ต้องแก้ไขแต่ละหน้า เพิ่มเหตุการณ์ 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"]));
                    }
                }

            }

        }
    }

0

คุณสามารถแทนที่คุณสมบัติ DefaultTagFormat ของสคริปต์หรือสไตล์

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

0

สำหรับการแก้ไขปัญหานี้ในแอปพลิเคชัน ASP.Net Ajax ของฉันฉันได้สร้างส่วนขยายจากนั้นเรียกในหน้าต้นแบบ

สำหรับรายละเอียดเพิ่มเติมที่คุณสามารถไปถึงการเชื่อมโยง


0

วิธีที่ง่ายและชาญฉลาดในการติดตั้งเวอร์ชัน css ในแอปพลิเคชัน. net ตามแนวคิดด้านล่าง .. ไม่จำเป็นต้องเขียนโค้ดส่วนหลัง

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

สิ่งนี้จะบังคับให้ดาวน์โหลดในทุก ๆ การแสดงผลหน้าแม้ว่าไฟล์จะไม่มีการเปลี่ยนแปลงเลยก็ตาม
Thanasis Ioannidis

@ThanasisIoannidis สามารถใช้เมื่อมีการเปลี่ยนแปลงไฟล์เป็นประจำ อีกทางเลือกหนึ่งคือเพิ่มคีย์ appVersion ใน web.config และใช้กับชื่อไฟล์ .. แต่คุณต้องอัปเดตเมื่อคุณปล่อยแอปพลิเคชันสำหรับ prod
SantoshK

-1

ปัญหาหลักในการทำเช่นนี้ส่วนใหญ่คุณจะต้องจำไว้ว่าต้องอัปเดตหมายเลขเวอร์ชันของคุณในโค้ดของคุณทุกครั้งที่คุณทำการเปลี่ยนแปลงใด ๆ กับไฟล์ 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" />

ซึ่งจะบังคับให้มีการร้องขอไฟล์จากเซิร์ฟเวอร์ทุกครั้งซึ่งหมายความว่าไซต์ของคุณจะไม่มีประสิทธิภาพในการโหลดหน้าเว็บเนื่องจากไฟล์เหล่านั้นจะไม่ถูกแคชและจะใช้แบนด์วิดท์ที่ไม่จำเป็นในแต่ละครั้ง

โดยพื้นฐานแล้วหากคุณจำได้ว่าต้องอัปเดตหมายเลขเวอร์ชันทุกครั้งที่มีการเปลี่ยนแปลงคุณสามารถหลีกเลี่ยงวิธีการดำเนินการได้


9
และใช้แบนด์วิดท์จำนวนมากด้วย
Darren Kopp

2
ใช่แล้วคุณไม่ต้องการ JS เวอร์ชันใหม่ในการโหลดแต่ละหน้า ... คุณแค่ต้องการให้เบราว์เซอร์มองหาเวอร์ชันใหม่ทุกครั้งที่คุณมีเวอร์ชันที่อัปเดตจริงๆ
kingdango

นี่เป็นที่ยอมรับอย่างสมบูรณ์แบบสำหรับโซลูชัน temp บนไฟล์ css ขนาด 50KB ในขณะที่กำลังพัฒนา +1
Colbs

-2

สำหรับเพจ ASP.NET ฉันกำลังใช้สิ่งต่อไปนี้

ก่อน

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

หลังจาก (บังคับให้โหลดซ้ำ)

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

การเพิ่ม DateTime.Now Ticks ทำงานได้ดีมาก


ใช่ปัญหาอยู่ที่แบนด์วิดท์ - เหมือนในความคิดเห็นด้านบนstackoverflow.com/a/2185918/59508
kiev
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.