/// <summary> /// Generates the JavaScript for the call to setOptions to set the options for an object /// (the JL object itself, an appender or a logger). /// </summary> /// <param name="parentName"> /// JavaScript variable that holds the element. /// </param> /// <param name="xe"> /// XML element. The attributes on this element will provide the values for the options. /// </param> /// <param name="attributeInfos"> /// Describes which attributes to use as options and how to validate them. /// /// As regards attributeInfos that have a SubTagName: /// * The value of such an attribute is an array, for example [ 'a', 'b' ] /// * If there are no child elements with the given sub tag name, there is no value, and no entry for that attributeinfo in /// the generated setOption. /// * If there is only one child element and it does not have an attribute, the value is an empty array []. /// </param> /// <param name="initialAttributeValues"> /// Initial attribute values. The elements found in xe will be added to this. /// If null, this method will create an empty collection itself. /// </param> /// <param name="sb"> /// The JS code is added to this. /// </param> /// <param name="validate"> /// If not null, this method is called on the generated attribute values. This can be used to throw an exception /// if the given parameters are not valid. /// </param> public static void ProcessOptionAttributes(string parentName, XmlElement xe, IEnumerable <AttributeInfo> attributeInfos, AttributeValueCollection initialAttributeValues, StringBuilder sb, Action <AttributeValueCollection> validate = null) { var attributeValues = initialAttributeValues ?? new AttributeValueCollection(); XmlHelpers.ProcessAttributes(xe, attributeInfos, attributeValues); if (validate != null) { validate(attributeValues); } JavaScriptHelpers.GenerateSetOptions(parentName, attributeValues, 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); } }