11

Javascript ファイルを返すコントローラー アクションがあります。ビューからこのファイルを参照でき、正常に動作します。他の JS ファイルと一緒に System.Web.Optimization.Bundle に入れたいと思います。

私は本質的にこれをやろうとしています:

new Bundle().Include("~/DynamicScript/UrlDictionary");

バンドル内の他のファイルは正常にレンダリングされますが、これは無視されます。この動作を見ると、アプリケーションがルーティング インフラストラクチャを介して URL を解決できるようになる前にバンドルが処理されるか、またはバンドル コンポーネントがその解決を可能にするような方法でファイルを要求していないことが推測されます。

誰かが私のためにそれを確認し、および/またはここで良い方向に私を向けることができれば、それは大歓迎です.

4

3 に答える 3

5

このシナリオで私が行ったことは次のとおりです。「Bundle Result」を定義してから、Controller メソッドで名前で Bundle を返しました。クライアント キャッシュの最適化として ETag (If-None-Match ヘッダー) を使用しています。

例えば:

public ActionResult ReturnFooBundle()
{
    return new BundleResult("foo", TimeSpan.FromDays(7));
}

BundleResult の実装は次のとおりです。

public class BundleResult
    : ActionResult
{
    private class BundleInfo
    {
        public string BundleETag;
        public DateTime LastModified;
        public Bundle TheBundle;
        public BundleResponse Response;
    }

    private static Dictionary<string, BundleInfo> _bundleCache = new Dictionary<string, BundleInfo>();

    public string BundleName { get; private set; }
    public TimeSpan CacheExpiry { get; private set; }

    public BundleResult(string bundleName, TimeSpan cacheExpiry)
    {
        BundleName = bundleName;
        CacheExpiry = cacheExpiry;
    }
    public override void ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.Clear();
        BundleInfo bundleInfo = GetBundle(context.HttpContext);

        string requestETag = context.HttpContext.Request.Headers["If-None-Match"];
        if (!string.IsNullOrEmpty(requestETag) && (requestETag == bundleInfo.BundleETag))
        {
            context.HttpContext.Response.StatusCode = (int)HttpStatusCode.NotModified;
            context.HttpContext.Response.StatusDescription = "Not Modified";
            return;
        }
        else
        {
            BundleResponse bundleResponse = bundleInfo.Response;
            HttpResponseBase response = context.HttpContext.Response;
            response.Write(bundleResponse.Content);
            response.ContentType = bundleResponse.ContentType;

            HttpCachePolicyBase cache = response.Cache;
            cache.SetCacheability(HttpCacheability.ServerAndPrivate);
            cache.SetLastModified(bundleInfo.LastModified);
            cache.SetETag(bundleInfo.BundleETag);
        }
    }

    private BundleInfo GetBundle(HttpContextBase context)
    {
        // lookup the BundleResponse
        BundleInfo retVal;
        lock (_bundleCache)
        {
            _bundleCache.TryGetValue(BundleName, out retVal);
        }
        if(retVal != null)
        {
#if DEBUG
            // see if the contents have been modified.
            BundleContext bundleContext = new BundleContext(context, BundleTable.Bundles, BundleName);
            DateTime lastModified = retVal.TheBundle.EnumerateFiles(bundleContext).Select(fi => fi.LastWriteTimeUtc).Max();
            if (lastModified > retVal.LastModified)
            {
                // regenerate the bundleInfo
                retVal = null;
            }
#endif
        }
        if (retVal == null)
        {
            string rawBundleName = BundleTable.Bundles.ResolveBundleUrl(BundleName);
            string hash = rawBundleName.Substring(rawBundleName.IndexOf("?v=") + 3);
            Bundle bundle = BundleTable.Bundles.GetBundleFor(BundleName);
            BundleContext bundleContext = new BundleContext(context, BundleTable.Bundles, BundleName);
            BundleResponse bundleResponse = bundle.GenerateBundleResponse(bundleContext);
            DateTime lastModified = bundle.EnumerateFiles(bundleContext).Select(fi => fi.LastWriteTimeUtc).Max();
            retVal = new BundleInfo
            {
                BundleETag = hash,
                Response = bundleResponse,
                TheBundle = bundle,
                LastModified = lastModified,
            };
            lock (_bundleCache)
            {
                _bundleCache[BundleName] = retVal;
            }
        }
        return retVal;
    }
}
于 2013-04-03T00:52:30.330 に答える
5

これは非常に実行可能だと思いますが、解決策に入る前に、最初のヒットでバンドルが作成され、再利用されることを思い出してください。つまり、「動的」スクリプトはすべてグローバルである必要があります (つまり、特定のユーザーなど)。これが、一般に静的 js ファイルのみを許可する理由です。そうは言っても...バージョン番号などの変数をjsに貼り付けたい状況を想像できます(ただし、その場合、個人的にはAjax/JSONを使用して取得します)。

その方法は、 Bundleから派生型を作成することだと思います。その中で、EnumerateFiles メソッドを上書きします。最初に、base.EnumerateFiles を列挙してから、独自の仮想ファイルを含めます。

次のようなもの (注: テストされていないコード):

public class VirtualMethodBundle : Bundle
{
    private List<VirtualFile> _virtualContent = new List<VirtualFile>();

    public override IEnumerable<VirtualFile> EnumerateFiles(BundleContext context)
    {
        foreach(var file in base.EnumerateFiles(context))
        {
            yield return file;
        }

        foreach(var virtual in _virtualContent)
        {
            yield return virtual;
        }
    }

    public void AddCustomFile(VirtualFile file)
    {
        _virtualContent.Add(method);
    }
}

次に、Open/Name メソッドをオーバーライドし、そこに動的コンテンツを返す特別なVirtualFile定義型を用意します。

public class MethodBasedVirtualFile : VirtualFile
{
    private readonly Func<string> _contentFactory;
    private readonly string _path;

    public MethodBasedVirtualFile(string path, Func<string> contentFactory)
    {
        _path = path;
        _contentFactory = contentFactory;
    }

    public override string Name { get { return _path; } }

    public override Stream Open()
    {
        MemoryStream stream = new MemoryStream();
        StreamWriter writer = new StreamWriter(stream);
        writer.Write(_contentFactory());
        writer.Flush();
        stream.Position = 0;
        return stream;
    }
}

それで、それをすべて使用するには...

var bundle = new VirtualMethodBundle();
bundle.Include(... real files ...);
bundle.AddCustomFile(
    new MethodBasedVirtualFile("~/DynamicScript/UrlDictionary",
    ... the method that creates the content of that script...)
);

賢い場合は、URL パスを取得し、MVC を使用して必要に応じてコンテンツを自動的に取得する UrlVirtualFile を作成できます。

于 2013-01-26T07:47:30.147 に答える
0

バンドル システムは、アプリケーション ルートではなく、物理ファイルのみをサポートします。

于 2012-11-13T07:35:13.877 に答える