2011-04-28 15 views
9

Vì vậy, tôi đã đọc this stackoverflow post về "tự động hóa" trong ASP.NET MVC cho tệp CSS/JS và đã tự hỏi chiến lược "tốt nhất" là làm điều này.Tự động hóa CSS/JS trong ASP.NET MVC?

Giải pháp được cung cấp chèn số lắp ráp - nghĩa là mọi lần bạn xuất bản - nó sẽ thay đổi mọi tệp SINGLE là không lý tưởng vì nếu bạn sửa đổi chỉ 1 * .css hoặc * .js thì nó sẽ thay đổi mỗi và mọi tệp.

1) Làm thế nào nó có thể được thực hiện chỉ cho "tệp duy nhất" thay vì sử dụng trang web rộng lắp ráp bằng cách sử dụng ngày sửa đổi hoặc một cái gì đó trên IIS7?

2) Ngoài ra nếu tôi có một số loại tài sản "tĩnh" như - http://static.domain.com/js/123.js - làm cách nào tôi có thể sử dụng viết lại để gửi tệp mới nhất cho yêu cầu nếu ai đó đã tích hợp liên kết tĩnh này vào trang web của họ?

tức là http://static.domain.com/js/123.js là liên kết và khi có yêu cầu - hãy kiểm tra và gửi tệp mới nhất?

+0

Thành thực mà nói, nếu bạn đang nhóm thì mọi tệp SINGLE sẽ có nghĩa là, các tệp được nén 2-5 được rút gọn. Tôi nghĩ đó là một giải pháp âm thanh. – Worthy7

Trả lời

4

1) Sử dụng thời gian sửa đổi tệp thay thế. Dưới đây là một ví dụ:

public static string GeneratePathWithTime(string cssFileName) 
{ 
    var serverFilePath = server.MapPath("~/static/" + cssFileName); 
    var version = File.GetLastWriteTime(serverFilePath).ToString("yyyyMMddhhmmss"); 
    return string.Format("/static/{0}/{1}", version, cssFileName); 
} 

này sẽ tạo ra một con đường như "/static/201109231100/style.css" cho "style.css" (giả sử các bạn style.css nằm trong thư mục static). Sau đó, bạn sẽ thêm quy tắc ghi đè trong IIS để viết lại "/static/201109231100/style.css" thành "/static/style.css". Số phiên bản sẽ chỉ được thay đổi khi tệp css đã được sửa đổi và chỉ áp dụng cho các tệp đã sửa đổi.

2) Bạn có thể xử lý yêu cầu đến 123.js qua HttpModule và gửi nội dung mới nhất của nó, nhưng tôi không nghĩ bạn có thể đảm bảo yêu cầu nhận phiên bản mới nhất. Nó phụ thuộc vào cách trình duyệt xử lý bộ nhớ cache của nó. Bạn có thể đặt thời gian hết hạn trước đó (ví dụ, một phút trước) trong tiêu đề phản hồi của bạn để cho trình duyệt luôn tải xuống lại tệp nhưng tất cả tùy thuộc vào chính trình duyệt để quyết định có tải xuống lại tệp hay không . Đó là lý do tại sao chúng tôi cần tạo một đường dẫn khác cho các tệp đã sửa đổi của chúng tôi mỗi lần chúng tôi cập nhật tệp của chúng tôi trong câu hỏi của bạn 1), trình duyệt sẽ luôn cố tải xuống tệp nếu URL chưa bao giờ được truy cập trước đó.

+2

Bạn không cần cấu hình các quy tắc viết lại trong IIS - MVC hỗ trợ định hướng ** Định tuyến **! –

+0

Chắc chắn. Và không chỉ MVC. Bạn cũng có thể viết một trình xử lý yêu cầu và đăng ký nó trong web.config hoặc sử dụng Global.asax. Chúng cũng được hỗ trợ. Viết lại IIS chỉ là một trong nhiều giải pháp. Tôi recommand IIS viết lại vì nó xử lý các yêu cầu trước khi .net runtime và có thể dễ dàng cấu hình mà không cần thay đổi mã của bạn. – Miller

+0

Bạn nói đúng, như của ASP.NET 4, Routing cũng có sẵn trong ASP.NET Core (bên ngoài MVC). Tuy nhiên, tôi đã đề cập đến MVC kể từ khi câu hỏi được gắn thẻ với nó. –

3

Bạn có thể muốn xem qua Blogpost của Dean Hume MVC and the HTML5 Application Cache. Trong bài đó, ông chỉ ra một cách tao nhã của tự động xử lý phiên bản theo yêu cầu, sử dụng một thư viện lớp của @ShirtlessKirk:

@Url.Content("~/Content/Site.css").AppendHash(Request) 
+0

Chỉ cần một lời cảnh cáo đối với bất kỳ ai tình cờ gặp câu trả lời này - kỹ thuật này dựa vào Application Cache, dường như không còn được dùng nữa: https://developer.mozilla.org/en/docs/Web/HTML/Using_the_application_cache – Orilux

3

Tôi đã viết một Helper Url mà hiện các macro theo dõi đối với tôi.

public static string CacheBustedContent(this UrlHelper helper, string contentPath) 
{ 
    var path = string.Empty; 

    if (helper.RequestContext.HttpContext.Cache["static-resource-" + contentPath] == null) 
    { 
     var fullpath = helper.RequestContext.HttpContext.Server.MapPath(contentPath); 
     var md5 = GetMD5HashFromFile(fullpath); 
     path = helper.Content(contentPath) + "?v=" + md5; 

     helper.RequestContext.HttpContext.Cache.Add("static-resource-" + contentPath, path, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(24, 0, 0), System.Web.Caching.CacheItemPriority.Default, null); 
    } 
    else 
    { 
     path = helper.RequestContext.HttpContext.Cache["static-resource-" + contentPath].ToString(); 
    } 

    return path; 
} 

Bạn có thể thay thế GetMD5HashFromFile() với CRC hoặc bất kỳ loại khác của cuộc gọi mà tạo ra một chuỗi duy nhất dựa trên nội dung hoặc sửa đổi lần cuối cập nhật của tập tin.

Nhược điểm là điều này sẽ được gọi bất cứ khi nào bộ nhớ cache bị vô hiệu. Và nếu bạn thay đổi tệp trực tiếp bằng cách nào đó, nhưng không đặt lại nhóm ứng dụng, có thể bạn sẽ cần phải chạm vào web.config để tải tệp xuống để tải lại chính xác.

+1

Điều đó nói rằng, Tôi thực sự thích SquishIt cho minifying, kết hợp và cachebusting cả javascript và css. http://www.codethinked.com/squishit-the-friendly-aspnet-javascript-and-css-squisher – davewasthere

9

Cách tôi giải quyết vấn đề này là thêm tự động chuyển sang dự án MVC của tôi trong Assembly2 thông tin .cs tập tin như vậy:

Change 
[assembly: AssemblyVersion("1.0.0.0")] 
to  
[assembly: AssemblyVersion("1.0.*")] 

Điều này có nghĩa rằng mỗi khi dự án được xây dựng, nó sẽ có một phiên bản lắp ráp mới mà là cao hơn so với trước đó. Bây giờ bạn có số phiên bản duy nhất của mình.

Sau đó tôi tạo một lớp UrlHelperExtension rằng sẽ giúp tôi có được những thông tin này khi tôi cần nó trong quan điểm của tôi:

public static class UrlHelperExtensions 
{ 
    public static string ContentVersioned(this UrlHelper self, string contentPath) 
    { 
     string versionedContentPath = contentPath + "?v=" + Assembly.GetAssembly(typeof(UrlHelperExtensions)).GetName().Version.ToString(); 
     return self.Content(versionedContentPath); 
    } 
} 

Bạn có thể dễ dàng thêm một số phiên bản để quan điểm của bạn theo cách sau đây:

<link href="@Url.ContentVersioned("style.css")" rel="stylesheet" type="text/css" /> 

Khi xem mã nguồn trang web của bạn bây giờ bạn sẽ có cái gì đó trông giống như

<link href="style.css?v=1.0.4809.30029" rel="stylesheet" type="text/css" /> 
+0

Tôi gặp lỗi ** Không quá tải cho phương pháp 'ContentVersioned' nhận 1 đối số ** tôi đang thực hiện Anjyr

+0

Giải pháp tuyệt vời! – mrpotocnik

+0

@Anjyr dựa trên đề xuất ở trên và giả sử bạn có phần mở rộng ContentVersioned như trên thay đổi src='~/Scripts/demoproject/@FileVersioning.ContentVersioned (‌ "custom.js") ' thành src =' @ Url.ContentVersioned ("~/full/path/to/custom.js") ' – mrpotocnik

2

CẬP NHẬT: Phiên bản trước không hoạt động trên Azure, tôi đã đơn giản hóa và sửa chữa bên dưới. (Lưu ý, để làm việc này trong chế độ phát triển với IIS Express, bạn sẽ cần phải cài đặt URL Rewrite 2.0 từ Microsoft http://www.iis.net/downloads/microsoft/url-rewrite - nó sử dụng trình cài đặt WebPi, đảm bảo đóng Visual Studio trước)

Nếu bạn muốn thay đổi tên thật của các tệp, thay vì thêm một chuỗi truy vấn (một số proxy/trình duyệt bị bỏ qua cho các tệp tĩnh) Bạn có thể làm theo các bước sau: (Tôi biết đây là một bài đăng cũ, nhưng tôi đã chạy qua nó trong khi phát triển một giải pháp :

làm thế nào để làm điều đó: Auto-increment phiên bản lắp ráp mỗi khi dự án được xây dựng và sử dụng con số đó cho một tập tin tĩnh chuyển trên tái cụ thể các nguồn bạn muốn tiếp tục làm mới. (do đó, something.js được bao gồm dưới dạng something.v1234.js với 1234 tự động thay đổi mỗi khi dự án được xây dựng) - Tôi cũng đã thêm một số chức năng bổ sung để đảm bảo rằng các tệp .min.js được sử dụng trong các tệp sản xuất và tệp thường xuyên được sử dụng Khi gỡ lỗi (Tôi đang sử dụng WebGrease để tự động hóa quá trình rút gọn) Một điều tốt đẹp về giải pháp này là nó hoạt động ở chế độ cục bộ/dev cũng như sản xuất. (Tôi đang sử dụng Visual Studio 2015/Net 4.6, nhưng tôi tin rằng điều này sẽ làm việc trong các phiên bản trước đó cũng

Bước 1:. Enable auto-increment về lắp ráp khi xây dựng Trong tập tin AssemblyInfo.cs (tìm thấy theo "thuộc tính" của dự án của bạn thay đổi những dòng sau:

[assembly: AssemblyVersion("1.0.0.0")] 
[assembly: AssemblyFileVersion("1.0.0.0")] 

để

[assembly: AssemblyVersion("1.0.*")] 
//[assembly: AssemblyFileVersion("1.0.0.0")] 

Bước 2: Thiết lập url REW rite trong web.config cho các tệp có sên phiên bản được nhúng (xem bước 3)

Trong web.config (phần chính cho dự án) thêm các quy tắc sau vào phần <system.webServer> Tôi đặt trực tiếp sau thẻ kết thúc </httpProtocol>.

<rewrite> 
    <rules> 
    <rule name="static-autoversion"> 
     <match url="^(.*)([.]v[0-9]+)([.](js|css))$" /> 
     <action type="Rewrite" url="{R:1}{R:3}" /> 
    </rule> 
    <rule name="static-autoversion-min"> 
     <match url="^(.*)([.]v[0-9]+)([.]min[.](js|css))$" /> 
     <action type="Rewrite" url="{R:1}{R:3}" /> 
    </rule> 
    </rules> 
</rewrite> 

Bước 3: Biến Cài đặt ứng dụng để đọc phiên bản lắp ráp hiện tại của bạn và tạo sên phiên bản trong js của bạn và các tập tin css.

trong Global.asax.cs (tìm thấy trong thư mục gốc của dự án) thêm đoạn mã sau vào protected void Application_Start() (sau khi các dòng Register)

  // setup application variables to write versions in razor (including .min extension when not debugging) 
      string addMin = ".min"; 
      if (System.Diagnostics.Debugger.IsAttached) { addMin = ""; } // don't use minified files when executing locally 
      Application["JSVer"] = "v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString().Replace('.','0') + addMin + ".js"; 
      Application["CSSVer"] = "v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString().Replace('.', '0') + addMin + ".css"; 

Bước 4: Thay đổi liên kết src trong Razor xem bằng cách sử dụng các biến ứng dụng chúng tôi thiết lập trong Global.asax.cs

@HttpContext.Current.Application["CSSVer"] 
@HttpContext.Current.Application["JSVer"] 

Ví dụ, trong _Layout.cshtml của tôi, trong phần đầu của tôi, tôi có khối mã sau đây cho stylesheets:

<!-- Load all stylesheets --> 
<link rel='stylesheet' href='https://fontastic.s3.amazonaws.com/8NNKTYdfdJLQS3D4kHqhLT/icons.css' /> 
<link rel='stylesheet' href='/Content/css/[email protected]["CSSVer"]' /> 
<link rel='stylesheet' media='(min-width: 700px)' href='/Content/css/[email protected]["CSSVer"]' /> 
<link rel='stylesheet' media='(min-width: 700px)' href='/Content/css/[email protected]["CSSVer"]' /> 
@RenderSection("PageCSS", required: false) 

Một vài điều cần lưu ý ở đây: 1) có không có phần mở rộng trên tệp. 2) cũng không có .min. Cả hai đều được xử lý bởi các mã trong Global.asax.cs

Tương tự như vậy, (cũng trong _Layout.cs) trong phần của tôi javascript: Tôi có đoạn mã sau:

<script src="~/Scripts/all3bnd100.min.js" type="text/javascript"></script> 
<script src="~/Scripts/[email protected]["JSVer"]" type="text/javascript"></script> 
@RenderSection("scripts", required: false) 

Các tập tin đầu tiên là một bó của tất cả thư viện của bên thứ ba mà tôi đã tạo theo cách thủ công với WebGrease. Nếu tôi thêm hoặc thay đổi bất kỳ tệp nào trong gói (hiếm khi xảy ra) thì tôi đổi tên tệp theo cách thủ công thành all3bnd101.min.js, all3bnd102.min.js, v.v. Tệp này không khớp với trình xử lý ghi đè, vì vậy sẽ vẫn được lưu trong bộ nhớ cache trên trình duyệt của khách hàng cho đến khi bạn đóng gói lại/thay đổi tên theo cách thủ công.

Tệp thứ hai là ui.js (tệp này sẽ được viết dưới dạng ui.v12345123.js hoặc ui.v12345123.min.js tùy thuộc vào việc bạn đang chạy trong chế độ gỡ lỗi hay không) Điều này sẽ được xử lý/viết lại. (Bạn có thể đặt một breakpoint trong Application_OnBeginRequest của Global.asax.cs để xem nó hoạt động)

thảo luận đầy đủ về vấn đề này tại địa chỉ: Simplified Auto-Versioning of Javascript/CSS in ASP.NET MVC 5 to stop caching issues (works in Azure and Locally) With or Without URL Rewrite(trong đó có một cách để làm điều đó KHÔNG URL Rewrite)

+0

đơn giản và sạch sẽ ... nhờ richard. – Bharat