Jos*_*ltz 11 asp.net asp.net-mvc asp.net-mvc-4 bundling-and-minification
我有一个控制器动作,返回Javascript文件.我可以从我的视图中引用此文件,它工作正常.我想把它与其他JS文件一起放在System.Web.Optimization.Bundle中.
我试图这样做,基本上:
new Bundle().Include("~/DynamicScript/UrlDictionary");
Run Code Online (Sandbox Code Playgroud)
我的Bundle中的其他文件被渲染得很好,但是这个被忽略了.看到这种行为,我的假设是在应用程序能够通过路由基础结构解析URL之前处理捆绑,或者捆绑组件不会以允许该解决方案发生的方式请求文件.
如果有人能够为我确认这一点和/或在这里向我指出一个好的方向,那将非常感激.
我认为这是非常可行的 - 但在我进入我的解决方案之前 - 请记住,捆绑包是在第一次打击时创建的并且被重用 - 这意味着任何"动态"脚本仍然必须是全局的(即它不能依赖于特定用户等).这就是为什么它通常只允许静态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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后你会有一个特殊的VirtualFile定义类型,它会覆盖Open/Name方法并在那里返回你的动态内容......就像.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
那么你可以使用它......
var bundle = new VirtualMethodBundle();
bundle.Include(... real files ...);
bundle.AddCustomFile(
new MethodBasedVirtualFile("~/DynamicScript/UrlDictionary",
... the method that creates the content of that script...)
);
Run Code Online (Sandbox Code Playgroud)
如果你聪明,你可以制作一个UrlVirtualFile,它接受url路径并使用MVC在需要时自动获取内容.
这是我针对此场景所做的操作。我定义了一个“Bundle Result”,然后在我的控制器方法中,仅按名称返回了一个 Bundle。我使用 ETags(If-None-Match Header)作为客户端缓存的优化。
例如:
public ActionResult ReturnFooBundle()
{
return new BundleResult("foo", TimeSpan.FromDays(7));
}
Run Code Online (Sandbox Code Playgroud)
这是 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;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2086 次 |
| 最近记录: |