📄 toolkitscriptmanager.cs
字号:
using (StreamWriter outputWriter = new StreamWriter(outputStream))
{
// Get the list of scripts to combine
List<ScriptEntry> scriptEntries = DeserializeScriptEntries(HttpUtility.UrlDecode(combinedScripts), false);
// Write the scripts
WriteScripts(scriptEntries, outputWriter);
// Write the ASP.NET AJAX script notification code
outputWriter.WriteLine("if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();");
// Write a handler to run on page load and update the hidden field tracking scripts loaded in the browser
outputWriter.WriteLine(string.Format(CultureInfo.InvariantCulture,
"(function() {{" +
"var fn = function() {{" +
"$get('{0}').value += '{1}';" +
"Sys.Application.remove_load(fn);" +
"}};" +
"Sys.Application.add_load(fn);" +
"}})();", hiddenFieldName, SerializeScriptEntries(scriptEntries, true)));
}
output = true;
}
return output;
}
/// <summary>
/// Writes scripts (including localized script resources) to the specified stream
/// </summary>
/// <param name="scriptEntries">list of scripts to write</param>
/// <param name="outputWriter">writer for output stream</param>
private static void WriteScripts(List<ScriptEntry> scriptEntries, TextWriter outputWriter)
{
foreach (ScriptEntry scriptEntry in scriptEntries)
{
if (!scriptEntry.Loaded)
{
if (!IsScriptCombinable(scriptEntry))
{
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Combined script request includes uncombinable script \"{0}\".", scriptEntry.Name));
}
// This script hasn't been loaded by the browser, so add it to the combined script file
outputWriter.Write("//START ");
outputWriter.WriteLine(scriptEntry.Name);
string script = scriptEntry.GetScript();
if (WebResourceRegex.IsMatch(script))
{
// This script uses script substitution which isn't supported yet, so throw an exception since it's too late to fix
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "ToolkitScriptManager does not support <%= WebResource/ScriptResource(...) %> substitution as used by script file \"{0}\".", scriptEntry.Name));
}
outputWriter.WriteLine(script);
// Save current culture and set the specified culture
CultureInfo currentUiCulture = Thread.CurrentThread.CurrentUICulture;
try
{
try
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(scriptEntry.Culture);
}
catch (ArgumentException)
{
// Invalid culture; proceed with default culture (just as for unsupported cultures)
}
// Write out the associated script resources (if any) in the proper culture
Assembly scriptAssembly = scriptEntry.LoadAssembly();
foreach (ScriptResourceAttribute scriptResourceAttribute in scriptAssembly.GetCustomAttributes(typeof(ScriptResourceAttribute), false))
{
if (scriptResourceAttribute.ScriptName == scriptEntry.Name)
{
// Found a matching script resource; write it out
outputWriter.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}={{", scriptResourceAttribute.TypeName));
// Get the script resource name (without the trailing ".resources")
string scriptResourceName = scriptResourceAttribute.ScriptResourceName;
if (scriptResourceName.EndsWith(".resources", StringComparison.OrdinalIgnoreCase))
{
scriptResourceName = scriptResourceName.Substring(0, scriptResourceName.Length - 10);
}
// Load a ResourceManager/ResourceSet and walk through the list to output them all
System.Resources.ResourceManager resourceManager = new System.Resources.ResourceManager(scriptResourceName, scriptAssembly);
using (System.Resources.ResourceSet resourceSet = resourceManager.GetResourceSet(CultureInfo.InvariantCulture, true, true))
{
bool first = true;
foreach (System.Collections.DictionaryEntry de in resourceSet)
{
if (!first)
{
// Need a comma between all entries
outputWriter.Write(",");
}
// Output the entry
string name = (string)de.Key;
string value = resourceManager.GetString(name);
outputWriter.Write(string.Format(CultureInfo.InvariantCulture, "\"{0}\":\"{1}\"", QuoteString(name), QuoteString(value)));
first = false;
}
}
outputWriter.WriteLine("};");
}
}
}
finally
{
// Restore culture
Thread.CurrentThread.CurrentUICulture = currentUiCulture;
}
// Done with this script
outputWriter.Write("//END ");
outputWriter.WriteLine(scriptEntry.Name);
}
// This script is now (or will be soon) loaded by the browser
scriptEntry.Loaded = true;
}
}
/// <summary>
/// Checks if the specified ScriptEntry is combinable
/// </summary>
/// <param name="scriptEntry">ScriptEntry to check</param>
/// <returns>true iff combinable</returns>
private static bool IsScriptCombinable(ScriptEntry scriptEntry)
{
// Load the script's assembly and look for ScriptCombineAttribute
bool combinable = false;
Assembly assembly = scriptEntry.LoadAssembly();
foreach (ScriptCombineAttribute scriptCombineAttribute in assembly.GetCustomAttributes(typeof(ScriptCombineAttribute), false))
{
if (string.IsNullOrEmpty(scriptCombineAttribute.IncludeScripts))
{
// If the IncludeScripts property is empty, all scripts are combinable by default
combinable = true;
}
else
{
// IncludeScripts specifies the combinable scripts
foreach (string includeScript in scriptCombineAttribute.IncludeScripts.Split(','))
{
// If this script name matches, it's combinable
if (0 == string.Compare(scriptEntry.Name, includeScript.Trim(), StringComparison.OrdinalIgnoreCase))
{
combinable = true;
break;
}
}
}
if (!string.IsNullOrEmpty(scriptCombineAttribute.ExcludeScripts))
{
// ExcludeScripts specifies the non-combinable scripts (and overrides IncludeScripts)
foreach (string excludeScript in scriptCombineAttribute.ExcludeScripts.Split(','))
{
// If the script name matches, it's not combinable
if (0 == string.Compare(scriptEntry.Name, excludeScript.Trim(), StringComparison.OrdinalIgnoreCase))
{
combinable = false;
break;
}
}
}
}
if (combinable)
{
// Make sure the script has an associated WebResourceAttribute (else ScriptManager wouldn't have served it)
bool correspondingWebResourceAttribute = false;
foreach (WebResourceAttribute webResourceAttribute in assembly.GetCustomAttributes(typeof(WebResourceAttribute), false))
{
if (scriptEntry.Name == webResourceAttribute.WebResource)
{
correspondingWebResourceAttribute = true;
break;
}
}
// Don't allow it to be combined if not
combinable &= correspondingWebResourceAttribute;
}
return combinable;
}
/// <summary>
/// Serialize a list of ScriptEntries
/// </summary>
/// <remarks>
/// Serialized list looks like:
/// ;Assembly1.dll Version=1:Culture:MVID1:ScriptName1Hash:ScriptName2Hash;Assembly2.dll Version=2:Culture:MVID1:ScriptName3Hash
/// </remarks>
/// <param name="scriptEntries">list of scripts to serialize</param>
/// <param name="allScripts">true iff all scripts should be serialized; otherwise only not loaded ones</param>
/// <returns>serialized list</returns>
private static string SerializeScriptEntries(List<ScriptEntry> scriptEntries, bool allScripts)
{
// Serialized string must never be null (';' is safe)
StringBuilder serializedScriptEntries = new StringBuilder(";");
string currentAssembly = null;
foreach (ScriptEntry scriptEntry in scriptEntries)
{
if (allScripts || !scriptEntry.Loaded)
{
// Serializing this script name
if (currentAssembly != scriptEntry.Assembly)
{
// It's a different assembly, so serialize the assembly name and Culture.MVID value first
serializedScriptEntries.Append(";");
serializedScriptEntries.Append(scriptEntry.Assembly);
serializedScriptEntries.Append(":");
serializedScriptEntries.Append(CultureInfo.CurrentUICulture.IetfLanguageTag);
serializedScriptEntries.Append(":");
serializedScriptEntries.Append(scriptEntry.LoadAssembly().ManifestModule.ModuleVersionId);
currentAssembly = scriptEntry.Assembly;
}
// Serialize the script name hash
serializedScriptEntries.Append(":");
serializedScriptEntries.Append(scriptEntry.Name.GetHashCode().ToString("x", CultureInfo.InvariantCulture));
}
}
return serializedScriptEntries.ToString();
}
/// <summary>
/// Deserialize a list of ScriptEntries
/// </summary>
/// <remarks>
/// Serialized list looks like:
/// ;Assembly1.dll Version=1:Culture:MVID1:ScriptName1Hash:ScriptName2Hash;Assembly2.dll Version=2:Culture:MVID1:ScriptName3Hash
/// </remarks>
/// <param name="serializedScriptEntries">serialized list</param>
/// <param name="loaded">loaded state of the serialized scripts</param>
/// <returns>list of scripts</returns>
private static List<ScriptEntry> DeserializeScriptEntries(string serializedScriptEntries, bool loaded)
{
List<ScriptEntry> scriptEntries = new List<ScriptEntry>();
foreach (string assemblyScripts in serializedScriptEntries.Split(';'))
{
// Deserialize this assembly's scripts
string assembly = null;
string culture = null;
string mvid = null;
Dictionary<string, string> resourceNameHashToResourceName = null;
foreach (string script in assemblyScripts.Split(':'))
{
if (null == assembly)
{
// Haven't got the assembly name yet; this is it
assembly = script;
}
else if (null == culture)
{
// Haven't got the culture value yet; this is it
culture = script;
}
else if (null == mvid)
{
// Haven't got the MVID value yet; this is it
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -