有什么建议吗?我也看到其他问题中有很多关于检查 Requestreduce 的反应,但它们都来自同一个用户。
处理这两种情况的最佳方法是什么?
谢谢!
你可以采取的一种方法是,在应用程序启动时动态构建捆绑包。因此,如果你的脚本位于~/scripts
中,你可以这样做:
Bundle bundle = new Bundle("~/scripts/js", new JsMinify());
if (includeJquery == true) {
bundle.IncludeDirectory("~/scripts", "jquery-*");
bundle.IncludeDirectory("~/scripts", "jquery-ui*");
}
if (includeAwesomenes == true) {
bundle.IncludeDirectory("~/scripts", "awesomeness.js");
}
BundleTable.Bundles.Add(bundle);
那么你的标记可以看起来像这样
@Scripts.Render("~/Scripts/Libs/js")
注意:我正在使用最新的系统.web.optimization NuGet包(现在是Microsoft.AspNet.Web.Optimization),它位于此处。Scott Hanselman在他的博客文章中有很好的介绍。
public static IHtmlString RenderStyles(this HtmlHelper helper, params string[] additionalPaths)
{
var page = helper.ViewDataContainer as WebPageExecutingBase;
if (page != null && page.VirtualPath.StartsWith("~/"))
{
var virtualPath = "~/bundles" + page.VirtualPath.Substring(1);
if (BundleTable.Bundles.GetBundleFor(virtualPath) == null)
{
var defaultPath = page.VirtualPath + ".css";
BundleTable.Bundles.Add(new StyleBundle(virtualPath).Include(defaultPath).Include(additionalPaths));
}
return MvcHtmlString.Create(@"<link href=""" + HttpUtility.HtmlAttributeEncode(BundleTable.Bundles.ResolveBundleUrl(virtualPath)) + @""" rel=""stylesheet""/>");
}
return MvcHtmlString.Empty;
}
public static IHtmlString RenderScripts(this HtmlHelper helper, params string[] additionalPaths)
{
var page = helper.ViewDataContainer as WebPageExecutingBase;
if (page != null && page.VirtualPath.StartsWith("~/"))
{
var virtualPath = "~/bundles" + page.VirtualPath.Substring(1);
if (BundleTable.Bundles.GetBundleFor(virtualPath) == null)
{
var defaultPath = page.VirtualPath + ".js";
BundleTable.Bundles.Add(new ScriptBundle(virtualPath).Include(defaultPath).Include(additionalPaths));
}
return MvcHtmlString.Create(@"<script src=""" + HttpUtility.HtmlAttributeEncode(BundleTable.Bundles.ResolveBundleUrl(virtualPath)) + @"""></script>");
}
return MvcHtmlString.Empty;
}
用法
~/views/Home/Test1.cshtml
~/Views/Home/Test1.cshtml.css
~/Views/Home/Test1.cshtml.js
在Test1.cshtml中
@model object
@{
// init
}@{
}@section MainContent {
{<div>@{
if ("work" != "fun")
{
{<hr/>}
}
}</div>}
}@{
}@section Scripts {@{
{@Html.RenderScripts()}
}@{
}@section Styles {@{
{@Html.RenderStyles()}
}}
我们早期考虑支持动态捆绑,但是这种方法的根本问题在于多服务器场景(即云)无法正常工作。如果所有捆绑包未事先定义,则发送到处理页面请求的不同服务器上的任何捆绑包请求都将收到404响应(因为捆绑包定义仅存在于处理页面请求的服务器上)。因此,我建议提前创建所有捆绑包,这是主要的情况。动态配置捆绑包也可能有效,但这不是完全支持的场景。
<script src="@Url.Content("http://localhost/CardGame/bundles/jquery")" type="text/javascript"></script>
这样的方式对我来说不起作用。响应500。 - Kevkong更新:不确定是否重要,但我正在使用MVC 5.2.3和Visual Studio 2015,问题有点旧。
然而,我在_viewStart.cshtml中创建了动态捆绑。我所做的是创建一个帮助类,将捆绑存储在捆绑字典中。然后在应用程序启动时,我从字典中提取它们并注册它们。我还制作了一个静态布尔值“bundlesInitialzed”,以便捆绑只添加到字典一次。
示例帮助程序:
public static class KBApplicationCore: .....
{
private static Dictionary<string, Bundle> _bundleDictionary = new Dictionary<string, Bundle>();
public static bool BundlesFinalized { get { return _BundlesFinalized; } }
/// <summary>
/// Add a bundle to the bundle dictionary
/// </summary>
/// <param name="bundle"></param>
/// <returns></returns>
public static bool RegisterBundle(Bundle bundle)
{
if (bundle == null)
throw new ArgumentNullException("bundle");
if (_BundlesFinalized)
throw new InvalidOperationException("The bundles have been finalized and frozen, you can only finalize the bundles once as an app pool recycle is needed to change the bundles afterwards!");
if (_bundleDictionary.ContainsKey(bundle.Path))
return false;
_bundleDictionary.Add(bundle.Path, bundle);
return true;
}
/// <summary>
/// Finalize the bundles, which commits them to the BundleTable.Bundles collection, respects the web.config's debug setting for optimizations
/// </summary>
public static void FinalizeBundles()
{
FinalizeBundles(null);
}
/// <summary>
/// Finalize the bundles, which commits them to the BundleTable.Bundles collection
/// </summary>
/// <param name="forceMinimize">Null = Respect web.config debug setting, True force minification regardless of web.config, False force no minification regardless of web.config</param>
public static void FinalizeBundles(bool? forceMinimize)
{
var bundles = BundleTable.Bundles;
foreach (var bundle in _bundleDictionary.Values)
{
bundles.Add(bundle);
}
if (forceMinimize != null)
BundleTable.EnableOptimizations = forceMinimize.Value;
_BundlesFinalized = true;
}
}
示例_ViewStart.cshtml
@{
var bundles = BundleTable.Bundles;
var baseUrl = string.Concat("~/App_Plugins/", KBApplicationCore.PackageManifest.FolderName, "/");
//Maybe there is a better way to do this, the goal is to make the bundle configurable without having to recompile the code
if (!KBApplicationCore.BundlesFinalized)
{
//Note, you need to reset the application pool in order for any changes here to be reloaded as the BundlesFinalized property is a static field that will only reset to false when the app restarts.
Bundle mainScripts = new ScriptBundle("~/bundles/scripts/main.js");
mainScripts.Include(new string[] {
baseUrl + "Assets/lib/jquery/jquery.js",
baseUrl + "Assets/lib/jquery/plugins/jqcloud/jqcloud.js",
baseUrl + "Assets/lib/bootstrap/js/bootstrap.js",
baseUrl + "Assets/lib/bootstrap/plugins/treeview/bootstrap-treeview.js",
baseUrl + "Assets/lib/angular/angular.js",
baseUrl + "Assets/lib/ckEditor/ckEditor.js"
});
KBApplicationCore.RegisterBundle(mainScripts);
Bundle appScripts = new ScriptBundle("~/bundles/scripts/app.js");
appScripts.Include(new string[] {
baseUrl + "Assets/app/app.js",
baseUrl + "Assets/app/services/*.js",
baseUrl + "Assets/app/directives/*.js",
baseUrl + "Assets/app/controllers/*.js"
});
KBApplicationCore.RegisterBundle(appScripts);
Bundle mainStyles = new StyleBundle("~/bundles/styles/main.css");
mainStyles.Include(new string[] {
baseUrl + "Assets/lib/bootstrap/build/less/bootstrap.less",
baseUrl + "Assets/lib/bootstrap/plugins/treeview/bootstrap-treeview.css",
baseUrl + "Assets/lib/ckeditor/contents.css",
baseUrl + "Assets/lib/font-awesome/less/font-awesome.less",
baseUrl + "Assets/styles/tlckb.less"
});
mainStyles.Transforms.Add(new BundleTransformer.Core.Transformers.CssTransformer());
mainStyles.Transforms.Add(new CssMinify());
mainStyles.Orderer = new BundleTransformer.Core.Orderers.NullOrderer();
KBApplicationCore.RegisterBundle(mainStyles);
KBApplicationCore.FinalizeBundles(true); //true = Force Optimizations, false = Force non Optmizations, null = respect web.config which is the same as calling the parameterless constructor.
}
}
注意:应更新为使用线程锁定以防止第一个请求退出之前的2个请求进入捆绑代码。
这个工作原理是视图启动在应用程序池重置后的第一个站点请求上运行。它调用helper上的RegisterBundle并将ScriptBundle或StyleBundle按照调用RegisterBundles的顺序传递给字典。
当调用FinalizeBundles时,您可以指定True,这将强制进行优化,而不管web.config debug设置如何,或者将其保留为空或使用没有该参数的构造函数,以使其遵守web.config设置。传递false将强制它不使用优化,即使debug为true。FinalizeBundles在bundles表中注册bundles并将_BundlesFinalized设置为true。
一旦完成,尝试再次调用RegisterBundle将引发异常,此时已经冻结。
此设置允许您添加新的bundles到view start并重置应用程序池以使其生效。我编写此内容的最初目标是因为我正在制作其他人将使用的东西,因此我希望他们能够完全更改前端UI,而无需重新构建源代码以更改bundles。