diff --git a/src/Shared/Enums/AspNetRequestLayoutOutputFormat.cs b/src/Shared/Enums/AspNetRequestLayoutOutputFormat.cs index a27c71f2..1ef9fb7d 100644 --- a/src/Shared/Enums/AspNetRequestLayoutOutputFormat.cs +++ b/src/Shared/Enums/AspNetRequestLayoutOutputFormat.cs @@ -1,3 +1,5 @@ +using System; + namespace NLog.Web.Enums { /// @@ -10,9 +12,20 @@ public enum AspNetRequestLayoutOutputFormat /// Flat = 0, + /// + /// Use this format for rendering the output value as a json-array + /// + JsonArray = 1, + /// /// Use this format for rendering the output value as a json formatted string. /// - Json = 1 + [Obsolete("Replaced by JsonArray. Marked obsolete with NLog 5.0")] + Json = 1, + + /// + /// Use this format for rendering the output value as a json-dictionary + /// + JsonDictionary = 2, } } \ No newline at end of file diff --git a/src/Shared/LayoutRenderers/AspNetLayoutMultiValueRendererBase.cs b/src/Shared/LayoutRenderers/AspNetLayoutMultiValueRendererBase.cs index 95ba4a61..cbda1845 100644 --- a/src/Shared/LayoutRenderers/AspNetLayoutMultiValueRendererBase.cs +++ b/src/Shared/LayoutRenderers/AspNetLayoutMultiValueRendererBase.cs @@ -46,10 +46,20 @@ public string ValueSeparator } /// - /// Single item in array? Only used for - /// Mutliple items are always in an array. + /// Get or set whether single key/value-pair be rendered as Json-Array. /// - public bool SingleAsArray { get; set; } = true; + [Obsolete("Replaced by OutputFormat = JsonArray / JsonDictionary. Marked obsolete with NLog.Web ver. 5.0")] + public bool SingleAsArray + { + get => OutputFormat != AspNetRequestLayoutOutputFormat.JsonDictionary; + set + { + if (!value) + OutputFormat = AspNetRequestLayoutOutputFormat.JsonDictionary; + else if (OutputFormat == AspNetRequestLayoutOutputFormat.JsonDictionary) + OutputFormat = AspNetRequestLayoutOutputFormat.JsonArray; + } + } /// /// Determines how the output is rendered. Possible Value: FLAT, JSON. Default is FLAT. @@ -61,17 +71,6 @@ public string ValueSeparator /// public bool ValuesOnly { get; set; } - /// - /// Serialize multiple key/value pairs - /// - /// The key/value pairs. - /// Add to this builder. - [Obsolete("use SerializePairs with logEvent to support Layouts for Separator. This overload will be removed in NLog.Web(aspNetCore) 5")] - protected void SerializePairs(IEnumerable> pairs, StringBuilder builder) - { - SerializePairs(pairs, builder, null); - } - /// /// Serialize multiple key/value pairs /// @@ -85,7 +84,8 @@ protected void SerializePairs(IEnumerable> pairs, S case AspNetRequestLayoutOutputFormat.Flat: SerializePairsFlat(pairs, builder, logEvent); break; - case AspNetRequestLayoutOutputFormat.Json: + case AspNetRequestLayoutOutputFormat.JsonArray: + case AspNetRequestLayoutOutputFormat.JsonDictionary: SerializePairsJson(pairs, builder); break; } @@ -94,35 +94,40 @@ protected void SerializePairs(IEnumerable> pairs, S private void SerializePairsJson(IEnumerable> pairs, StringBuilder builder) { var firstItem = true; - var pairsList = pairs.ToList(); - - if (pairsList.Count == 0) - { - return; - } - - var addArray = pairsList.Count > (SingleAsArray || ValuesOnly ? 0 : 1); - - if (addArray) - { - builder.Append('['); - } - foreach (var kpv in pairsList) + foreach (var item in pairs) { - if (!firstItem) + if (firstItem) + { + if (!ValuesOnly && OutputFormat == AspNetRequestLayoutOutputFormat.JsonDictionary) + { + builder.Append("{"); + } + else + { + builder.Append("["); + } + } + else { builder.Append(','); } - SerializePairJson(builder, kpv); + SerializePairJson(builder, item); firstItem = false; } - if (addArray) + if (!firstItem) { - builder.Append(']'); + if (!ValuesOnly && OutputFormat == AspNetRequestLayoutOutputFormat.JsonDictionary) + { + builder.Append("}"); + } + else + { + builder.Append("]"); + } } } @@ -134,7 +139,10 @@ private void SerializePairJson(StringBuilder builder, KeyValuePair /// /// ${aspnet-request-cookie:OutputFormat=Flat} - /// ${aspnet-request-cookie:OutputFormat=Json} - /// ${aspnet-request-cookie:OutputFormat=Json:CookieNames=username} - /// ${aspnet-request-cookie:OutputFormat=Json:Exclude=access_token} + /// ${aspnet-request-cookie:OutputFormat=JsonArray} + /// ${aspnet-request-cookie:OutputFormat=JsonDictionary} + /// ${aspnet-request-cookie:OutputFormat=JsonDictionary:CookieNames=username} + /// ${aspnet-request-cookie:OutputFormat=JsonDictionary:Exclude=access_token} /// /// [LayoutRenderer("aspnet-request-cookie")] @@ -94,7 +95,7 @@ private IEnumerable> GetCookieValues(HttpCookieColl continue; } - if (OutputFormat == AspNetRequestLayoutOutputFormat.Json) + if (OutputFormat != AspNetRequestLayoutOutputFormat.Flat) { // Split multi-valued cookie, as allowed for in the HttpCookie API for backwards compatibility with classic ASP var isFirst = true; diff --git a/src/Shared/LayoutRenderers/AspNetRequestHeadersLayoutRenderer.cs b/src/Shared/LayoutRenderers/AspNetRequestHeadersLayoutRenderer.cs index b452adc2..691ff366 100644 --- a/src/Shared/LayoutRenderers/AspNetRequestHeadersLayoutRenderer.cs +++ b/src/Shared/LayoutRenderers/AspNetRequestHeadersLayoutRenderer.cs @@ -20,9 +20,10 @@ namespace NLog.Web.LayoutRenderers /// /// /// ${aspnet-request-headers:OutputFormat=Flat} - /// ${aspnet-request-headers:OutputFormat=Json} - /// ${aspnet-request-headers:OutputFormat=Json:HeaderNames=username} - /// ${aspnet-request-headers:OutputFormat=Json:Exclude=access_token} + /// ${aspnet-request-headers:OutputFormat=JsonArray} + /// ${aspnet-request-headers:OutputFormat=JsonDictionary} + /// ${aspnet-request-headers:OutputFormat=JsonDictionary:HeaderNames=username} + /// ${aspnet-request-headers:OutputFormat=JsonDictionary:Exclude=access_token} /// /// [LayoutRenderer("aspnet-request-headers")] diff --git a/src/Shared/LayoutRenderers/AspNetRequestQueryStringLayoutRenderer.cs b/src/Shared/LayoutRenderers/AspNetRequestQueryStringLayoutRenderer.cs index f3aa0d39..5b1258e5 100644 --- a/src/Shared/LayoutRenderers/AspNetRequestQueryStringLayoutRenderer.cs +++ b/src/Shared/LayoutRenderers/AspNetRequestQueryStringLayoutRenderer.cs @@ -22,7 +22,8 @@ namespace NLog.Web.LayoutRenderers /// /// /// ${aspnet-request-querystring:OutputFormat=Flat} - /// ${aspnet-request-querystring:OutputFormat=Json} + /// ${aspnet-request-querystring:OutputFormat=JsonArray} + /// ${aspnet-request-querystring:OutputFormat=JsonDictionary} /// /// [LayoutRenderer("aspnet-request-querystring")] diff --git a/tests/Shared/LayoutRenderers/AspNetCookieLayoutRendererTests.cs b/tests/Shared/LayoutRenderers/AspNetCookieLayoutRendererTests.cs index 0f9bcb45..c2418ff3 100644 --- a/tests/Shared/LayoutRenderers/AspNetCookieLayoutRendererTests.cs +++ b/tests/Shared/LayoutRenderers/AspNetCookieLayoutRendererTests.cs @@ -12,8 +12,6 @@ using Microsoft.Extensions.Primitives; #endif - - namespace NLog.Web.Tests.LayoutRenderers { public class AspNetCookieLayoutRendererTests : TestInvolvingAspNetHttpContext @@ -59,7 +57,7 @@ public void KeyNotFoundRendersEmptyString_Flat_Formatting() public void KeyNotFoundRendersEmptyString_Json_Formatting() { var renderer = CreateRenderer(); - renderer.OutputFormat = AspNetRequestLayoutOutputFormat.Json; + renderer.OutputFormat = AspNetRequestLayoutOutputFormat.JsonArray; renderer.CookieNames = new List { "notfound" }; string result = renderer.Render(new LogEventInfo()); @@ -143,24 +141,33 @@ public void KeyFoundRendersValue_Single_Cookie_Json_Formatting_no_array() var expectedResult = "{\"key\":\"TEST\"}"; var renderer = CreateRenderer(addSecondCookie: false); - renderer.OutputFormat = AspNetRequestLayoutOutputFormat.Json; - renderer.SingleAsArray = false; + renderer.OutputFormat = AspNetRequestLayoutOutputFormat.JsonDictionary; string result = renderer.Render(new LogEventInfo()); Assert.Equal(expectedResult, result); } - [Theory] - [InlineData(false)] - [InlineData(true)] - public void KeyFoundRendersValue_Multiple_Cookies_Json_Formatting(bool singleAsArray) + [Fact] + public void KeyFoundRendersValue_Multiple_Cookies_Json_Formatting() { var expectedResult = "[{\"key\":\"TEST\"},{\"Key1\":\"TEST1\"}]"; var renderer = CreateRenderer(); renderer.OutputFormat = AspNetRequestLayoutOutputFormat.Json; - renderer.SingleAsArray = singleAsArray; + + string result = renderer.Render(new LogEventInfo()); + + Assert.Equal(expectedResult, result); + } + + [Fact] + public void KeyFoundRendersValue_Multiple_Cookies_Json_Formatting_no_array() + { + var expectedResult = "{\"key\":\"TEST\",\"Key1\":\"TEST1\"}"; + + var renderer = CreateRenderer(); + renderer.OutputFormat = AspNetRequestLayoutOutputFormat.JsonDictionary; string result = renderer.Render(new LogEventInfo()); @@ -256,8 +263,7 @@ public void KeyFoundRendersValue_Single_Item_Json_Formatting_no_array_ValuesOnly var renderer = CreateRenderer(addSecondCookie: false); - renderer.OutputFormat = AspNetRequestLayoutOutputFormat.Json; - renderer.SingleAsArray = false; + renderer.OutputFormat = AspNetRequestLayoutOutputFormat.JsonDictionary; renderer.ValuesOnly = true; string result = renderer.Render(new LogEventInfo()); @@ -268,14 +274,13 @@ public void KeyFoundRendersValue_Single_Item_Json_Formatting_no_array_ValuesOnly [Theory] [InlineData(false)] [InlineData(true)] - public void KeyFoundRendersValue_Cookie_Multiple_Items_Json_Formatting_ValuesOnly(bool singleAsArray) + public void KeyFoundRendersValue_Cookie_Multiple_Items_Json_Formatting_ValuesOnly(bool valuesAsProperties) { var expectedResult = "[\"TEST\",\"TEST1\"]"; var renderer = CreateRenderer(); - renderer.OutputFormat = AspNetRequestLayoutOutputFormat.Json; - renderer.SingleAsArray = singleAsArray; + renderer.OutputFormat = AspNetRequestLayoutOutputFormat.JsonDictionary; renderer.ValuesOnly = true; string result = renderer.Render(new LogEventInfo()); diff --git a/tests/Shared/LayoutRenderers/AspNetQueryStringLayoutRendererTests.cs b/tests/Shared/LayoutRenderers/AspNetQueryStringLayoutRendererTests.cs index 3b55c7f2..da41abd2 100644 --- a/tests/Shared/LayoutRenderers/AspNetQueryStringLayoutRendererTests.cs +++ b/tests/Shared/LayoutRenderers/AspNetQueryStringLayoutRendererTests.cs @@ -152,14 +152,12 @@ public void MultipleValuesForOneKeyShouldWork() [Fact] public void MultipleValuesJsonQuoted() { - var expectedResult = @"{""Id"":""a'b,\""c\""""}"; var renderer = CreateAndMockRenderer(CreateTuple("Id", "a'b", "\"c\"")); renderer.QueryStringKeys = null; - renderer.OutputFormat = AspNetRequestLayoutOutputFormat.Json; - renderer.SingleAsArray = false; + renderer.OutputFormat = AspNetRequestLayoutOutputFormat.JsonDictionary; string result = renderer.Render(new LogEventInfo()); diff --git a/tests/Shared/LayoutRenderers/AspNetRequestHeadersLayoutRendererTests.cs b/tests/Shared/LayoutRenderers/AspNetRequestHeadersLayoutRendererTests.cs index 9fce3dfc..85ea1839 100644 --- a/tests/Shared/LayoutRenderers/AspNetRequestHeadersLayoutRendererTests.cs +++ b/tests/Shared/LayoutRenderers/AspNetRequestHeadersLayoutRendererTests.cs @@ -141,24 +141,33 @@ public void KeyFoundRendersValue_Single_Header_Json_Formatting_no_array() var expectedResult = "{\"key\":\"TEST\"}"; var renderer = CreateRenderer(addSecondHeader: false); - renderer.OutputFormat = AspNetRequestLayoutOutputFormat.Json; - renderer.SingleAsArray = false; + renderer.OutputFormat = AspNetRequestLayoutOutputFormat.JsonDictionary; string result = renderer.Render(new LogEventInfo()); Assert.Equal(expectedResult, result); } - [Theory] - [InlineData(false)] - [InlineData(true)] - public void KeyFoundRendersValue_Multiple_Headers_Json_Formatting(bool singleAsArray) + [Fact] + public void KeyFoundRendersValue_Multiple_Headers_Json_Formatting() { var expectedResult = "[{\"key\":\"TEST\"},{\"Key1\":\"TEST1\"}]"; var renderer = CreateRenderer(); renderer.OutputFormat = AspNetRequestLayoutOutputFormat.Json; - renderer.SingleAsArray = singleAsArray; + + string result = renderer.Render(new LogEventInfo()); + + Assert.Equal(expectedResult, result); + } + + [Fact] + public void KeyFoundRendersValue_Multiple_Headers_Json_Formatting_no_array() + { + var expectedResult = "{\"key\":\"TEST\",\"Key1\":\"TEST1\"}"; + + var renderer = CreateRenderer(); + renderer.OutputFormat = AspNetRequestLayoutOutputFormat.JsonDictionary; string result = renderer.Render(new LogEventInfo()); @@ -254,8 +263,7 @@ public void KeyFoundRendersValue_Single_Item_Json_Formatting_no_array_ValuesOnly var renderer = CreateRenderer(addSecondHeader: false); - renderer.OutputFormat = AspNetRequestLayoutOutputFormat.Json; - renderer.SingleAsArray = false; + renderer.OutputFormat = AspNetRequestLayoutOutputFormat.JsonDictionary; renderer.ValuesOnly = true; string result = renderer.Render(new LogEventInfo()); @@ -263,17 +271,14 @@ public void KeyFoundRendersValue_Single_Item_Json_Formatting_no_array_ValuesOnly Assert.Equal(expectedResult, result); } - [Theory] - [InlineData(false)] - [InlineData(true)] - public void KeyFoundRendersValue_Header_Multiple_Items_Json_Formatting_ValuesOnly(bool singleAsArray) + [Fact] + public void KeyFoundRendersValue_Header_Multiple_Items_Json_Formatting_ValuesOnly() { var expectedResult = "[\"TEST\",\"TEST1\"]"; var renderer = CreateRenderer(); - renderer.OutputFormat = AspNetRequestLayoutOutputFormat.Json; - renderer.SingleAsArray = singleAsArray; + renderer.OutputFormat = AspNetRequestLayoutOutputFormat.JsonDictionary; renderer.ValuesOnly = true; string result = renderer.Render(new LogEventInfo());