programing

MVC4에서 BundleCollection이 캐시된 스크립트 번들을 강제로 플러시하는 방법

closeapi 2023. 7. 5. 20:45
반응형

MVC4에서 BundleCollection이 캐시된 스크립트 번들을 강제로 플러시하는 방법

또는 Microsoft의 완전히 문서화되지 않은 API에 대해 걱정을 멈추고 코드를 작성하는 방법을 배웠습니다.공식적인 문서가 있습니까?System.Web.Optimization방석? 나는 도 찾을 없고 없고이 RC 하고 있기 때문입니다. 이는 왜냐하면 나는 확실히 찾을 수 없고, XML 문서가 없으며, 모든 블로그 게시물은 실질적으로 다른 RC API를 참조하기 때문입니다.아무후..

자바스크립트 종속성을 자동으로 해결하기 위해 코드를 작성하고 있으며 이러한 종속성에서 즉시 번들을 생성하고 있습니다.스크립트를 편집하거나 애플리케이션을 다시 시작하지 않고 번들에 영향을 미치는 변경을 수행하는 경우를 제외하고는 모든 작업이 제대로 수행됩니다.그래서 개발에 사용할 종속성의 캐싱을 비활성화하는 옵션을 추가했습니다.

겉보기에는 하만지, 겉에는기보.BundleTables에서는 번들 컬렉션이 변경된 경우에도 URL을 캐시합니다.예를 들어 번들을 다시 만들고 싶을 때 자체 코드에서 다음과 같은 작업을 수행합니다.

// remove an existing bundle
BundleTable.Bundles.Remove(BundleTable.Bundles.GetBundleFor(bundleAlias));

// recreate it.
var bundle = new ScriptBundle(bundleAlias);

// dependencies is a collection of objects representing scripts, 
// this creates a new bundle from that list. 

foreach (var item in dependencies)
{
    bundle.Include(item.Path);
}

// add the new bundle to the collection

BundleTable.Bundles.Add(bundle);

// bundleAlias is the same alias used previously to create the bundle,
// like "~/mybundle1" 

var bundleUrl = BundleTable.Bundles.ResolveBundleUrl(bundleAlias);

// returns something like "/mybundle1?v=hzBkDmqVAC8R_Nme4OYZ5qoq5fLBIhAGguKa28lYLfQ1"

동일한 별칭을 가진 번들을 제거하고 다시 만들 때마다 아무 일도 일어나지 않습니다.bundleUrl에서 돌아왔습니다.ResolveBundleUrl번들을 제거하고 다시 만들기 전과 동일합니다."동일"이란 번들의 새 내용을 반영하기 위해 내용 해시가 변경되지 않음을 의미합니다.

편집... 사실, 그것보다 훨씬 더 나빠요.번들 자체는 어떻게든 외부에 캐시됩니다.Bundles수집.브라우저가 스크립트를 캐시하지 못하도록 임의 해시만 생성하면 ASP.NET은 이전 스크립트를 반환합니다.그래서, 분명히, 보따리를 제거하는 것은BundleTable.Bundles실제로는 아무것도 하지 않습니다.

이 문제를 해결하기 위해 간단히 별칭을 변경할 수 있습니다. 개발에는 문제가 없지만 각 페이지 로드 후에 별칭을 더 이상 사용하지 않거나 모든 페이지 로드에서 크기가 커지는 번들 컬렉션을 사용해야 하기 때문에 이 아이디어는 마음에 들지 않습니다.운영 환경에서 이 기능을 계속 사용하면 큰 문제가 발생할 수 있습니다.

따라서 스크립트가 제공될 때 실제와 독립적으로 캐시됩니다.BundleTables.Bundles따라서 에도 URL을 모든하고 URL을 변경합니다.Bundles오브젝트는 캐시를 플러시하지 않으므로 새 항목(또는 이름이 다른 새 항목)만 사용됩니다.

행동이 이상해 보입니다...컬렉션에서 무언가를 제거하면 캐시에서 무언가가 제거됩니다.하지만 그렇지 않습니다.할 수 합니다.BundleCollection이 번들에 처음 액세스할 때 캐시한 것 대신에

내가 이걸 어떻게 할지 알아요?

게 .ResetAll목적을 알 수 없는 방법이지만 어쨌든 그것은 상황을 깨뜨릴 뿐이므로 그렇지 않습니다.

설명서에 대한 불만이 들리지만, 안타깝게도 이 기능은 여전히 빠르게 변경되고 있으며 설명서 생성은 약간의 지연이 있으며 거의 즉시 구식이 될 수 있습니다.Rick의 블로그 게시물은 최신이며, 저는 그동안 최신 정보를 퍼뜨리기 위해 여기에 있는 질문에도 답하려고 노력했습니다.우리는 현재 공식 코드플렉스 사이트를 설정하는 중이며, 이 사이트는 항상 최신 문서로 되어 있습니다.

이제 캐시에서 번들을 플러시하는 방법에 대한 구체적인 문제에 대해 말씀드리겠습니다.

  1. 합니다. 요된에 URL번, 즉, 키번 ASP.NET캐Context.Cache["System.Web.Optimization.Bundle:~/bundles/jquery"]또한 이 번들을 생성하는 데 사용된 모든 파일 및 디렉터리에 대해 캐시 종속성을 설정합니다.따라서 기본 파일 또는 디렉터리가 변경되면 캐시 항목이 플러시됩니다.

  2. 요청별로 BundleTable/BundleCollection의 라이브 업데이트는 지원하지 않습니다.완벽하게 지원되는 시나리오는 앱 시작 시 번들이 구성되는 것입니다(웹 팜 시나리오에서 모든 것이 제대로 작동하도록 하기 위한 것입니다. 그렇지 않으면 일부 번들 요청이 잘못된 서버로 전송될 경우 404개가 됩니다.코드 예제를 보면 특정 요청에 따라 번들 컬렉션을 동적으로 수정하려고 하는 것 같습니다.모든 종류의 번들 관리/재구성은 모든 것이 올바르게 설정되도록 앱 도메인 재설정이 수반되어야 합니다.

따라서 앱 도메인을 재활용하지 않고 번들 정의를 수정하지 마십시오.번들 내부의 실제 파일을 자유롭게 수정할 수 있습니다. 이 파일은 자동으로 검색되고 번들 URL에 대한 새 해시 코드를 생성해야 합니다.

저도 비슷한 문제가 있어요.
에서 우에서반리.BundleConfig저는 사용이 어떤 효과가 있는지 보려고 했습니다.BundleTable.EnableOptimizations = true.

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        BundleTable.EnableOptimizations = true;

        bundles.Add(...);
    }
}

모든 것이 잘 작동하고 있었습니다.
어느 순간 디버깅을 하다가 속성을 false로 설정했습니다.
번째)로드되지 않는 것 (jquery(jquery) /bundles/jquery?v=).

욕을 좀 한 후에 나는 생각합니다(?).저는 일들을 어떻게든 해결했습니다.추가시를 추가해 .bundles.Clear()그리고.bundles.ResetAll()등록이 시작되면 일이 다시 시작되어야 합니다.

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Clear();
        bundles.ResetAll();

        BundleTable.EnableOptimizations = false;

        bundles.Add(...);
    }
}

이 두 가지 방법을 실행해야 한다는 것을 깨달았습니다.EnableOptimizations소유물.

업데이트:

더 깊이 파고들면서 저는BundleTable.Bundles.ResolveBundleUrl그리고.@Scripts.Url번들 경로를 해결하는 데 문제가 있는 것 같습니다.

단순성을 위해 몇 가지 이미지를 추가했습니다.

image 1

최적화 기능을 끄고 스크립트 몇 개를 번들로 제공했습니다.

image 2

동일한 번들이 본문에 포함되어 있습니다.

image 3

@Scripts.Url의 "하는 반면 들의최 "화적된를" "경는제하동공"@Scripts.Render적절한 값을 생성합니다.
에도 같은 일이 발생합니다.BundleTable.Bundles.ResolveBundleUrl.

Visual Studio 2010 + MVC 4 + Framework를 사용하고 있습니다.넷 4.0.

웹 팜 시나리오 때문에 이것을 하지 말라는 Hao Kung의 권고를 염두에 두고, 저는 여러분이 이것을 하고 싶어할 수 있는 많은 시나리오가 있다고 생각합니다.솔루션은 다음과 같습니다.

BundleTable.Bundles.ResetAll(); //or something more specific if neccesary
var bundle = new Bundle("~/bundles/your-bundle-virtual-path");
//add your includes here or load them in from a config file

//this is where the magic happens
var context = new BundleContext(new HttpContextWrapper(HttpContext.Current), BundleTable.Bundles, bundle.Path);
bundle.UpdateCache(context, bundle.GenerateBundleResponse(context));

BundleTable.Bundles.Add(bundle);

언제든지 위 코드를 호출할 수 있으며 번들이 업데이트됩니다.Enable Optimization(최적화 사용)이 true 또는 false인 경우 모두 작동합니다. 즉, 디버그 또는 라이브 시나리오에서 올바른 마크업이 무시됩니다.

@Scripts.Render("~/bundles/your-bundle-virtual-path")

또한 재구축하지 않고 번들을 업데이트하는 데 문제가 발생했습니다.이해해야 할 중요한 사항은 다음과 같습니다.

  • 파일 경로가 변경되어도 번들이 업데이트되지 않습니다.
  • 번들의 가상 경로가 변경되면 번들이 업데이트됩니다.
  • 디스크의 파일이 변경되면 번들이 업데이트됩니다.

동적 번들링을 수행하는 경우 번들의 가상 경로가 파일 경로를 기반으로 하도록 코드를 작성할 수 있습니다.파일 경로를 해시하고 해당 해시를 번들의 가상 경로 끝에 추가하는 것이 좋습니다.이렇게 하면 파일 경로가 변경될 때 가상 경로와 번들이 업데이트됩니다.

문제를 해결한 코드는 다음과 같습니다.

    public static IHtmlString RenderStyleBundle(string bundlePath, string[] filePaths)
    {
        // Add a hash of the files onto the path to ensure that the filepaths have not changed.
        bundlePath = string.Format("{0}{1}", bundlePath, GetBundleHashForFiles(filePaths));

        var bundleIsRegistered = BundleTable
            .Bundles
            .GetRegisteredBundles()
            .Where(bundle => bundle.Path == bundlePath)
            .Any();

        if(!bundleIsRegistered)
        {
            var bundle = new StyleBundle(bundlePath);
            bundle.Include(filePaths);
            BundleTable.Bundles.Add(bundle);
        }

        return Styles.Render(bundlePath);
    }

    static string GetBundleHashForFiles(IEnumerable<string> filePaths)
    {
        // Create a unique hash for this set of files
        var aggregatedPaths = filePaths.Aggregate((pathString, next) => pathString + next);
        var Md5 = MD5.Create();
        var encodedPaths = Encoding.UTF8.GetBytes(aggregatedPaths);
        var hash = Md5.ComputeHash(encodedPaths);
        var bundlePath = hash.Aggregate(string.Empty, (hashString, next) => string.Format("{0}{1:x2}", hashString, next));
        return bundlePath;
    }

(StyleBundle 또는 ScriptBundle)에서 파생하여 생성자에 포함 항목을 추가하지 않은 다음 재정의하려고 시도했습니까?

public override IEnumerable<System.IO.FileInfo> EnumerateFiles(BundleContext context)

동적 스타일시트에 대해 이 작업을 수행하고 모든 요청에 대해 EnumerateFiles가 호출됩니다.그것은 아마도 가장 좋은 해결책은 아닐 것이지만 효과가 있습니다.

사용자가 백엔드에서 예쁜 버전을 변경할 때 스타일시트/스크립트가 자동으로 최소화되기를 원했던 움브라코 사이트의 번들 캐싱에서도 비슷한 문제가 발생했습니다.

이미 가지고 있던 코드는 (스타일시트의 onSaved 메서드에서) 다음과 같습니다.

 BundleTable.Bundles.Add(new StyleBundle("~/bundles/styles.min.css").Include(
                           "~/css/main.css"
                        ));

및 (Application Started 시):

BundleTable.EnableOptimizations = true;

아무리 노력해도 "~/bundles/styles.min.css" 파일은 바뀌지 않은 것 같습니다.제 페이지의 머리 부분에서, 저는 원래 스타일시트에 다음과 같이 로드하고 있었습니다.

<link rel="stylesheet" href="~/bundles/styles.min.css" />

그러나 이를 다음과 같이 변경하여 작동하게 되었습니다.

@Styles.Render("~/bundles/styles.min.css")

스타일.렌더 메소드는 파일 이름 끝에 쿼리 문자열을 삽입하는데, 위의 Hao가 설명한 캐시 키인 것 같습니다.

저에게 있어서, 그것은 그렇게 간단했습니다.이것이 저처럼 몇 시간 동안 이것을 검색하고 몇 년 된 게시물만 찾을 수 있었던 다른 사람에게 도움이 되기를 바랍니다!

언급URL : https://stackoverflow.com/questions/12317391/how-to-force-bundlecollection-to-flush-cached-script-bundles-in-mvc4

반응형