C# 如何使Microsoft Bundle输出JavaScript而不是HTML脚本标记
我正在构建一个基于ASP.NETMVC4的jQuery插件,我希望使用该标准 现在,通常情况下,当我使用捆绑机时,最终用途如下:C# 如何使Microsoft Bundle输出JavaScript而不是HTML脚本标记,c#,asp.net,asp.net-mvc-4,bundle,C#,Asp.net,Asp.net Mvc 4,Bundle,我正在构建一个基于ASP.NETMVC4的jQuery插件,我希望使用该标准 现在,通常情况下,当我使用捆绑机时,最终用途如下: @Scripts.Render(BundleConfig.jsBundleFile) 在调试中使用如下输出: <script src="/Scripts/..."></script> <script src="/Scripts/..."></script> <script src="/Scripts/..."&g
@Scripts.Render(BundleConfig.jsBundleFile)
在调试中使用如下输出:
<script src="/Scripts/..."></script>
<script src="/Scripts/..."></script>
<script src="/Scripts/..."></script>
<script src="/Scripts/..."></script>
<script src="/Scripts/..."></script>
<script src="/Scripts/..."></script>
在发行版中,我会得到缩小的内容
从这个例子中,我看到bundler在默认情况下无法做到这一点。但我想知道是有一个扩展可以做到这一点,还是另一个迷你库可以做到这一点?虽然我更喜欢微软捆绑包
在我自己关于如何扩展System.Web.Optimizer的研究中,我发现了System.Web.Optimization
项目,据说该项目到目前为止还不是开源的,这使得扩展对于没有真正研究它的人来说有点困难
编辑:我知道我不能真正扩展System.Web.Optimizer,所以我选择了一个折衷的解决方案,这就是我最终使用的解决方案
在控制器中:
public JavaScriptResult jQueryComponent()
{
JavaScriptResult ret = new JavaScriptResult();
ClientSettings Model = new ClientSettings();
#if DEBUG
List<string> jsFiles = App_Start.BundleConfig.Main.FilesToBeBundledJS;
StringBuilder bundleBuilder = new StringBuilder();
foreach (string file in jsFiles)
{
bundleBuilder.Append(System.IO.File.ReadAllText(Server.MapPath(file)));
}
ViewBag.bundledJS = bundleBuilder.ToString();
#else
StringBuilder urlBuilder = new StringBuilder("http://localhost");
int port = Request.Url.Port;
if (port != -1) {
urlBuilder.Append(':');
urlBuilder.Append(port);
}
urlBuilder.Append(Scripts.Url(App_Start.BundleConfig.Main.jsBundleFile));
WebClient wc = new WebClient();
byte[] raw = wc.DownloadData(urlBuilder.ToString());
string bundledJS = System.Text.Encoding.UTF8.GetString(raw);
ViewBag.bundledJS = bundledJS;
#endif
ret.Script = RenderRazorViewToString("~/Views/Main/jQueryComponent.cshtml", Model);
return ret;
}
private string RenderRazorViewToString(string viewName, object model)
{
ViewData.Model = model;
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
欢迎提出任何关于如何改进此功能的想法,以及对捆绑机的适当扩展。虽然有效,但这还远远不够理想,我很清楚这一点。
除非您有其他选择,否则请不要批评这种方法。创建自己的类和稳定的缩小器更容易 对于迷你型,您可以使用以下其中一种:
- (请注意,webfleed已经包含了Ajax Minifier,如果同时添加两个NuGet包,可能会发生冲突)
- 静止
- 包含一个
以保存每个捆绑包中的文件列表
- 在字典中,要保存捆绑包名称及其文件:
带有捆绑包名称dictionary
,以及文件名列表string
list
StringBuilder
,StringWriter
,StreamReader
,文件
)。如果需要模拟绑定器中的通配符名称,请使用目录
,或者使用正则表达式
类
读取的结果应该存储在静态字典中,该字典保存包名称和包内容(用于缓存,避免反复读取相同的文件)
最后,你需要缩小它
您可以根据两种不同的情况来切换minificacion:
- c#code
中调试的定义<代码>#endif这取决于在configuration manager中选择的解决方案配置:调试/发布#ifdef debug
JavaScriptCompressor jsCompressor = new JavaScriptCompressor();
jsCompressor.ObfuscateJavascript = true; // Optional
string minified = jsCompressor.Compress(originalScript);
使用MS Ajax缩小器缩小:
Minifier min = new Minifier();
string minified = min.MinifyJavaScript(originalScript);
您还应该将缩小的版本存储在静态字典中,以缓存它们
这是一个基本的工作示例:
public class MyMinifier
{
protected static Dictionary<string,List<string>> VirtualPathsInBundle
= new Dictionary<string, List<string>>();
protected static Dictionary<string, string> OriginalJavascriptInBundle
= new Dictionary<string, string>();
protected static Dictionary<string, string> MinifiedJavascriptInBundle
= new Dictionary<string, string>();
public static void AddBundle(string bundleName, params string[] virtualPaths)
{
VirtualPathsInBundle.Add(bundleName, virtualPaths.ToList());
}
public static string GetOriginalJavaScript(string bundleName)
{
if (!OriginalJavascriptInBundle.ContainsKey(bundleName))
{
var physicalFilePaths = VirtualPathsInBundle[bundleName]
.Select(vp => HttpContext.Current.Server.MapPath(vp));
// If you use wildcards, expand them here...
StringBuilder scripts = new StringBuilder();
foreach (var path in physicalFilePaths)
{
scripts.AppendFormat("// path: {0}", path);
scripts.AppendLine();
scripts.Append(File.ReadAllText(path));
}
OriginalJavascriptInBundle.Add(bundleName, scripts.ToString());
}
return OriginalJavascriptInBundle[bundleName];
}
public static string GetMinifiedJavaScript(string bundleName)
{
if (!MinifiedJavascriptInBundle.ContainsKey(bundleName))
{
Minifier minifier = new Minifier();
MinifiedJavascriptInBundle[bundleName]
= minifier.MinifyJavaScript(GetOriginalJavaScript(bundleName));
}
return MinifiedJavascriptInBundle[bundleName];
}
}
公共类MyMinifier
{
受保护的静态字典VirtualPathsInBundle
=新字典();
受保护的静态字典原始JavaScriptInBundle
=新字典();
受保护的静态字典MinifiedJavascriptInBundle
=新字典();
公共静态void AddBundle(字符串bundleName,参数string[]virtualPath)
{
添加(bundleName,virtualPath.ToList());
}
公共静态字符串GetOriginalJavaScript(字符串bundleName)
{
如果(!OriginalJavascriptInBundle.ContainsKey(bundleName))
{
var physicalfilepath=VirtualPathsInBundle[bundleName]
.Select(vp=>HttpContext.Current.Server.MapPath(vp));
//如果使用通配符,请在此处展开它们。。。
StringBuilder脚本=新建StringBuilder();
foreach(PhysicalFilePath中的变量路径)
{
AppendFormat(“//路径:{0}”,路径);
scripts.AppendLine();
scripts.Append(File.ReadAllText(path));
}
原始JavaScriptInBundle.Add(bundleName,scripts.ToString());
}
返回原始JavaScriptInBundle[bundleName];
}
公共静态字符串GetMinifiedJavaScript(字符串bundleName)
{
如果(!MinifiedJavascriptInBundle.ContainsKey(bundleName))
{
Minifier Minifier=新Minifier();
MinifiedJavascriptInBundle[bundleName]
=minifier.MinifyJavaScript(GetOriginalJavaScript(bundleName));
}
返回MinifiedJavascriptInBundle[bundleName];
}
}
您可以执行BundleHandler所做的操作:基于虚拟路径(与您将使用的虚拟路径相同)获取一个
@Script.Render
),然后编写
简言之:
@Html.Raw(BundleTable.Bundles.GetBundleFor("~/VIRTUALPATH").GenerateBundleResponse(new BundleContext(this.Context, BundleTable.Bundles, string.Empty)).Content)
编辑:要在调试中获取未统一的内容,我们可以做什么:再次获取捆绑包,但不是生成响应,而是创建并写入它们的内容()
您是否尝试过Visual studio Web Essentials插件内置的捆绑功能?这个bundler在编译时而不是运行时绑定,这似乎适合您的需要@Andrew我不是一个真正的插件迷(插件在公司内很难推广,除非它们是MS插件),但从快速浏览到我,这为项目创建了一个单独的缩小文件,我可以将其包含到我的项目中。我更喜欢Web中的解决方案。Optimizer是我可以更新文件(在已部署的项目上)并让它们为客户端组合成一个JS文件,也就是说,所有的缩小都是在运行时完成的,而不是在项目部署中。为什么开发jquery插件需要简单javascript中的所有.JS?我开发了很多,但我看不出原因。也许你不应该尝试这样做,而应该改变你面对这个问题的方式。如果我理解你为什么认为你需要这个,希望我能给你展示好的选择。我从来都不需要它,在生产中有几个插件。它不是一个组件
public class MyMinifier
{
protected static Dictionary<string,List<string>> VirtualPathsInBundle
= new Dictionary<string, List<string>>();
protected static Dictionary<string, string> OriginalJavascriptInBundle
= new Dictionary<string, string>();
protected static Dictionary<string, string> MinifiedJavascriptInBundle
= new Dictionary<string, string>();
public static void AddBundle(string bundleName, params string[] virtualPaths)
{
VirtualPathsInBundle.Add(bundleName, virtualPaths.ToList());
}
public static string GetOriginalJavaScript(string bundleName)
{
if (!OriginalJavascriptInBundle.ContainsKey(bundleName))
{
var physicalFilePaths = VirtualPathsInBundle[bundleName]
.Select(vp => HttpContext.Current.Server.MapPath(vp));
// If you use wildcards, expand them here...
StringBuilder scripts = new StringBuilder();
foreach (var path in physicalFilePaths)
{
scripts.AppendFormat("// path: {0}", path);
scripts.AppendLine();
scripts.Append(File.ReadAllText(path));
}
OriginalJavascriptInBundle.Add(bundleName, scripts.ToString());
}
return OriginalJavascriptInBundle[bundleName];
}
public static string GetMinifiedJavaScript(string bundleName)
{
if (!MinifiedJavascriptInBundle.ContainsKey(bundleName))
{
Minifier minifier = new Minifier();
MinifiedJavascriptInBundle[bundleName]
= minifier.MinifyJavaScript(GetOriginalJavaScript(bundleName));
}
return MinifiedJavascriptInBundle[bundleName];
}
}
@{
var context = new BundleContext(this.Context, BundleTable.Bundles, string.Empty);
var bundle = BundleTable.Bundles.GetBundleFor("~/VIRTUALPATH");
var response = bundle.GenerateBundleResponse(context);
var content = response.Content;
this.WriteLiteral(content);
}
@Html.Raw(BundleTable.Bundles.GetBundleFor("~/VIRTUALPATH").GenerateBundleResponse(new BundleContext(this.Context, BundleTable.Bundles, string.Empty)).Content)
@{
var context = new BundleContext(this.Context, BundleTable.Bundles, string.Empty);
var bundle = BundleTable.Bundles.GetBundleFor("~/VIRTUALPATH");
if (BundleTable.EnableOptimizations)
{
var response = bundle.GenerateBundleResponse(context);
var content = response.Content;
this.WriteLiteral(content);
}
else
{
var files = bundle.EnumerateFiles(context);
foreach (var file in files)
{
var stream = file.VirtualFile.Open();
using (var reader = new StreamReader(stream))
{
this.Output.Write("{0}{1}", reader.ReadToEnd(), bundle.ConcatenationToken);
}
}
}
}