// This version is not reliant on sitting in a web site, so can be unit tested. // generateClosure - if false, no function closure is generated around the generated JS code. Only set to false when unit testing. // Doing this assumes that jsnlog.js has loaded before the code generated by the method is executed. // // You want to set this to false during unit testing, because then you need direct access outside the closure of variables // that are private to the closure, specifically dummyappenders that store the log messages you receive, so you can unit test them. public void ProcessRootExec(XmlElement xe, StringBuilder sb, Func <string, string> virtualToAbsoluteFunc, string userIp, string requestId, bool generateClosure) { string loggerProductionLibraryVirtualPath = XmlHelpers.OptionalAttribute(xe, "productionLibraryPath", ""); bool loggerEnabled = bool.Parse(XmlHelpers.OptionalAttribute(xe, "enabled", "true", Constants.RegexBool)); string loggerProductionLibraryPath = null; if (!string.IsNullOrEmpty(loggerProductionLibraryVirtualPath)) { // Every hard coded path must be resolved. See the declaration of DefaultDefaultAjaxUrl loggerProductionLibraryPath = virtualToAbsoluteFunc(loggerProductionLibraryVirtualPath); } if (!loggerEnabled) { if (!string.IsNullOrWhiteSpace(loggerProductionLibraryPath)) { JavaScriptHelpers.WriteScriptTag(loggerProductionLibraryPath, sb); } JavaScriptHelpers.WriteJavaScriptBeginTag(sb); Utils.ProcessOptionAttributes(Constants.JsLogObjectName, xe, Constants.JSNLogAttributes, null, sb); JavaScriptHelpers.WriteJavaScriptEndTag(sb); return; } JavaScriptHelpers.WriteJavaScriptBeginTag(sb); if (generateClosure) { JavaScriptHelpers.WriteLine(string.Format("var {0} = function ({1}) {{", Constants.GlobalMethodCalledAfterJsnlogJsLoaded, Constants.JsLogObjectName), sb); } // Generate setOptions for JSNLog object itself AttributeValueCollection attributeValues = new AttributeValueCollection(); attributeValues[Constants.JsLogObjectClientIpOption] = new Value(userIp, new StringValue()); attributeValues[Constants.JsLogObjectRequestIdOption] = new Value(requestId, new StringValue()); // Set default value for defaultAjaxUrl attribute attributeValues[Constants.JsLogObjectDefaultAjaxUrlOption] = new Value(virtualToAbsoluteFunc(Constants.DefaultDefaultAjaxUrl), new StringValue()); Utils.ProcessOptionAttributes(Constants.JsLogObjectName, xe, Constants.JSNLogAttributes, attributeValues, sb); // Process all loggers and appenders Dictionary <string, string> appenderNames = new Dictionary <string, string>(); Sequence sequence = new Sequence(); // ----------------- // First process all assembly tags topLeveltagInfos = new List <XmlHelpers.TagInfo>( new[] { new XmlHelpers.TagInfo(Constants.TagAssembly, ProcessAssembly, Constants.AssemblyAttributes, (int)Constants.OrderNbr.Assembly) }); XmlHelpers.ProcessNodeList( xe.ChildNodes, topLeveltagInfos.Where(t => t.Tag == Constants.TagAssembly).ToList(), null, appenderNames, sequence, sb, string.Format("^{0}*", Constants.TagAssembly)); // ----------------- // The elements (if any) from external assemblies have now been loaded (with the assembly elements). // Now add the elements from the executing assembly after the external ones. // This way, logger elements are processed last - after any new appenders. AddAssemblyTagInfos(Assembly.GetExecutingAssembly()); // Now process the external and internal elements, but not the assembly elements. XmlHelpers.ProcessNodeList( xe.ChildNodes, topLeveltagInfos, null, appenderNames, sequence, sb, string.Format("^((?!{0}).)*$", Constants.TagAssembly)); // ------------- if (generateClosure) { // Generate code to execute the function, in case jsnlog.js has already been loaded. // Wrap in try catch, so if jsnlog.js hasn't been loaded, the resulting exception will be swallowed. JavaScriptHelpers.WriteLine(string.Format("}}; try {{ {0}({1}); }} catch(e) {{}};", Constants.GlobalMethodCalledAfterJsnlogJsLoaded, Constants.JsLogObjectName), sb); } JavaScriptHelpers.WriteJavaScriptEndTag(sb); // Write the script tag that loads jsnlog.js after the code generated from the web.config. // When using jsnlog.js as an AMD module or in a bundle, jsnlog.js will be loaded after that code as well, // and creating a similar situation in the default out of the box loading option makes it more likely // you pick up bugs during testing. if (!string.IsNullOrWhiteSpace(loggerProductionLibraryPath)) { JavaScriptHelpers.WriteScriptTag(loggerProductionLibraryPath, sb); } }
// This version is not reliant on sitting in a web site, so can be unit tested. // generateClosure - if false, no function closure is generated around the generated JS code. Only set to false when unit testing. // Doing this assumes that jsnlog.js has loaded before the code generated by the method is executed. // // You want to set this to false during unit testing, because then you need direct access outside the closure of variables // that are private to the closure, specifically dummyappenders that store the log messages you receive, so you can unit test them. public void ProcessRootExec(StringBuilder sb, Func <string, string> virtualToAbsoluteFunc, string userIp, string requestId, bool generateClosure) { Dictionary <string, string> appenderNames = new Dictionary <string, string>(); JsnlogConfiguration jsnlogConfiguration = JavascriptLogging.GetJsnlogConfiguration(); string loggerProductionLibraryVirtualPath = jsnlogConfiguration.productionLibraryPath; bool loggerEnabled = jsnlogConfiguration.enabled; string loggerProductionLibraryPath = null; if (!string.IsNullOrEmpty(loggerProductionLibraryVirtualPath)) { // Every hard coded path must be resolved. See the declaration of DefaultDefaultAjaxUrl loggerProductionLibraryPath = Utils.AbsoluteUrl(loggerProductionLibraryVirtualPath, virtualToAbsoluteFunc); } JavaScriptHelpers.WriteJavaScriptBeginTag(sb); if (generateClosure) { JavaScriptHelpers.WriteLine(string.Format("var {0} = function ({1}) {{", Constants.GlobalMethodCalledAfterJsnlogJsLoaded, Constants.JsLogObjectName), sb); } // Generate setOptions for JSNLog object itself var jsonFields = new List <string>(); JavaScriptHelpers.AddJsonField(jsonFields, Constants.JsLogObjectClientIpOption, userIp, new StringValue()); JavaScriptHelpers.AddJsonField(jsonFields, Constants.JsLogObjectRequestIdOption, requestId, new StringValue()); JavaScriptHelpers.GenerateSetOptions(Constants.JsLogObjectName, jsnlogConfiguration, appenderNames, virtualToAbsoluteFunc, sb, jsonFields); if (loggerEnabled) { // Process all loggers and appenders. First process the appenders, because the loggers can be // dependent on the appenders, and will use appenderNames to translate configuration appender names // to JavaScript names. int sequence = 0; GenerateCreateJavaScript(jsnlogConfiguration.ajaxAppenders, sb, virtualToAbsoluteFunc, appenderNames, ref sequence); GenerateCreateJavaScript(jsnlogConfiguration.consoleAppenders, sb, virtualToAbsoluteFunc, appenderNames, ref sequence); GenerateCreateJavaScript(jsnlogConfiguration.loggers, sb, virtualToAbsoluteFunc, appenderNames, ref sequence); } // ------------- if (generateClosure) { // Generate code to execute the function, in case jsnlog.js has already been loaded. // Wrap in try catch, so if jsnlog.js hasn't been loaded, the resulting exception will be swallowed. JavaScriptHelpers.WriteLine(string.Format("}}; try {{ {0}({1}); }} catch(e) {{}};", Constants.GlobalMethodCalledAfterJsnlogJsLoaded, Constants.JsLogObjectName), sb); } JavaScriptHelpers.WriteJavaScriptEndTag(sb); // Write the script tag that loads jsnlog.js after the code generated from the web.config. // When using jsnlog.js as an AMD module or in a bundle, jsnlog.js will be loaded after that code as well, // and creating a similar situation in the default out of the box loading option makes it more likely // you pick up bugs during testing. if (!string.IsNullOrWhiteSpace(loggerProductionLibraryPath)) { JavaScriptHelpers.WriteScriptTag(loggerProductionLibraryPath, sb); } }