diff --git a/CHANGELOG.MD b/CHANGELOG.MD index ed202bc3..782d88b6 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -4,6 +4,24 @@ See also [releases](https://github.com/NLog/NLog.Web/releases) and [milestones]( Date format: (year/month/day) +### Version 5.2.0 (2022/11/27) + +- **NLog.Web.AspNetCore** + - [#885](https://github.com/NLog/NLog.Web/pull/885) Changed LoadConfigurationFromAppSettings to prioritize current directory (#885) (@snakefoot) + - [#887](https://github.com/NLog/NLog.Web/pull/887) Changed AspNetAppBasePathLayoutRenderer to prioritize current directory (#887) (@snakefoot) + - [#890](https://github.com/NLog/NLog.Web/pull/890) Add ObjectPath to AspNetItemValueLayoutRenderer as better alternative to EvaluateAsNestedProperties (#890) (@bakgerman) + - [#889](https://github.com/NLog/NLog.Web/pull/889) Use CallerArgumentExpressionAttribute in helper method for throwing ArgumentNullException (#889) (@bakgerman) + - [#894](https://github.com/NLog/NLog.Web/pull/894) Use AspNetSessionValueLayoutRenderer in helper method for throwing ArgumentNullException (#894) (@snakefoot) + - [#891](https://github.com/NLog/NLog.Web/pull/891) Skip allocating RouteData when only need to lookup single value (#891) (@snakefoot) + - [#878](https://github.com/NLog/NLog.Web/pull/878) + [#879](https://github.com/NLog/NLog.Web/pull/879) Use RegisterConfigSettings instead of ConfigSettingLayoutRenderer (#878 + #879) (@snakefoot) + - [#894](https://github.com/NLog/NLog.Web/pull/894) Updated dependency NLog.Extensions.Logging v5.2.0 (#894) (@snakefoot) + +- **NLog.Web** + - [#890](https://github.com/NLog/NLog.Web/pull/890) Add ObjectPath to AspNetItemValueLayoutRenderer as better alternative to EvaluateAsNestedProperties (#890) (@bakgerman) + - [#894](https://github.com/NLog/NLog.Web/pull/894) Use AspNetSessionValueLayoutRenderer in helper method for throwing ArgumentNullException (#894) (@snakefoot) + - [#889](https://github.com/NLog/NLog.Web/pull/889) Use CallerArgumentExpressionAttribute in helper method for throwing ArgumentNullException (#889) (@bakgerman) + - [#894](https://github.com/NLog/NLog.Web/pull/894) Updated dependency NLog v5.1.0 (#894) (@snakefoot) + ### Version 5.1.5 (2022/10/26) - **NLog.Web.AspNetCore** diff --git a/appveyor.yml b/appveyor.yml index 7dae29f5..81230eb6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 5.1.0.{build} +version: 5.2.0.{build} clone_folder: c:\projects\nlogweb configuration: Release image: Visual Studio 2022 diff --git a/build.ps1 b/build.ps1 index e076fe50..8cd736bd 100644 --- a/build.ps1 +++ b/build.ps1 @@ -2,7 +2,7 @@ # creates NuGet package at \artifacts dotnet --version -$versionPrefix = "5.1.5" # Also update version for minor versions in appveyor.yml +$versionPrefix = "5.2.0" # Also update version for minor versions in appveyor.yml $versionSuffix = "" $versionFile = $versionPrefix + "." + ${env:APPVEYOR_BUILD_NUMBER} if ($env:APPVEYOR_PULL_REQUEST_NUMBER) { diff --git a/examples/ASP.NET 4.6.1/Visual Studio 2017/ASP.NET 4.6.1 - VS2017/packages.config b/examples/ASP.NET 4.6.1/Visual Studio 2017/ASP.NET 4.6.1 - VS2017/packages.config index 47dec917..aeba3130 100644 --- a/examples/ASP.NET 4.6.1/Visual Studio 2017/ASP.NET 4.6.1 - VS2017/packages.config +++ b/examples/ASP.NET 4.6.1/Visual Studio 2017/ASP.NET 4.6.1 - VS2017/packages.config @@ -12,7 +12,7 @@ - + \ No newline at end of file diff --git a/src/NLog.Web.AspNetCore/NLog.Web.AspNetCore.csproj b/src/NLog.Web.AspNetCore/NLog.Web.AspNetCore.csproj index d861addd..b607dcd0 100644 --- a/src/NLog.Web.AspNetCore/NLog.Web.AspNetCore.csproj +++ b/src/NLog.Web.AspNetCore/NLog.Web.AspNetCore.csproj @@ -21,8 +21,14 @@ Supported platforms: NLog.Web.AspNetCore logging;log;NLog;web;aspnet;aspnetcore;MVC;Microsoft.Extensions.Logging;httpcontext -- Introduced Introduced NET6 since LTS (@snakefoot) -- Updated NLog.Extensions.Logging to v5.1.0 (@snakefoot) +- Changed LoadConfigurationFromAppSettings to prioritize current directory (#885) (@snakefoot) +- Changed AspNetAppBasePathLayoutRenderer to prioritize current directory (#887) (@snakefoot) +- Add ObjectPath to AspNetItemValueLayoutRenderer as better alternative to EvaluateAsNestedProperties (#890) (@bakgerman) +- Add ObjectPath to AspNetSessionValueLayoutRenderer as better alternative to EvaluateAsNestedProperties (#894) (@snakefoot) +- Use CallerArgumentExpressionAttribute in helper method for throwing ArgumentNullException (#889) (@bakgerman) +- Skip allocating RouteData when only need to lookup single value (#891) (@snakefoot) +- Use RegisterConfigSettings instead of ConfigSettingLayoutRenderer (#878 + #879) (@snakefoot) +- Updated dependency NLog.Extensions.Logging v5.2.0 (#894) (@snakefoot) List of major changes in NLog 5.0: https://nlog-project.org/2022/05/16/nlog-5-0-finally-ready.html @@ -75,7 +81,7 @@ List of available Layout Renderers: https://nlog-project.org/config/?tab=layout- $(DefineConstants);ASP_NET_CORE;ASP_NET_CORE3 - + diff --git a/src/NLog.Web/NLog.Web.csproj b/src/NLog.Web/NLog.Web.csproj index 1298aa1f..96e33c5c 100644 --- a/src/NLog.Web/NLog.Web.csproj +++ b/src/NLog.Web/NLog.Web.csproj @@ -51,7 +51,7 @@ List of available Layout Renderers: https://nlog-project.org/config/?tab=layout- - + diff --git a/src/Shared/Internal/PropertyReader.cs b/src/Shared/Internal/PropertyReader.cs index 0d612d51..caa9a6af 100644 --- a/src/Shared/Internal/PropertyReader.cs +++ b/src/Shared/Internal/PropertyReader.cs @@ -4,6 +4,7 @@ namespace NLog.Web.Internal { + [Obsolete("Instead use ObjectPath. Marked obsolete with NLog.Web 5.2")] internal static class PropertyReader { /// @@ -14,6 +15,7 @@ internal static class PropertyReader /// function to get a value with this key /// evaluate as a nested property path. E.g. A.B is property B inside A. /// value + [Obsolete("Instead use ObjectPath. Marked obsolete with NLog.Web 5.2")] public static object GetValue(string key, T container, Func getVal, bool evaluateAsNestedProperties) { if (string.IsNullOrEmpty(key)) @@ -24,30 +26,7 @@ public static object GetValue(string key, T container, Func - /// Get value of a property - /// - /// key - /// Container to perform value lookup using key - /// function to get a value with this key - /// evaluate the string as a dot notated path to a aproperty in the object, returned by lookup by the key parameter - /// value - public static object GetValue(string key, T container, Func getVal, string objectPath) - { - if (string.IsNullOrEmpty(key)) - { - return null; - } - - var value = getVal(container, key); - if (value == null) - { - return null; - } - - return GetValueAsNestedProperties(value, objectPath); - } - + [Obsolete("Instead use ObjectPath. Marked obsolete with NLog.Web 5.2")] private static object GetValueAsNestedProperties(string key, T container, Func getVal) { var path = key.Contains('.') ? key.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries) : null; @@ -69,26 +48,7 @@ private static object GetValueAsNestedProperties(string key, T container, Fun return value; } - private static object GetValueAsNestedProperties(object value, string objectPath) - { - var path = objectPath.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); - - if (value != null && path?.Length > 0) - { - for (int i = 0; i < path.Length; ++i) - { - var propertyInfo = GetPropertyInfo(value, path[i]); - value = propertyInfo?.GetValue(value, null); - if (value == null) - { - break; - } - } - } - - return value; - } - + [Obsolete("Instead use ObjectPath. Marked obsolete with NLog.Web 5.2")] private static PropertyInfo GetPropertyInfo(object value, string propertyName) { #if !ASP_NET_CORE diff --git a/src/Shared/LayoutRenderers/AspNetItemValueLayoutRenderer.cs b/src/Shared/LayoutRenderers/AspNetItemValueLayoutRenderer.cs index d360f3c6..eeb600b2 100644 --- a/src/Shared/LayoutRenderers/AspNetItemValueLayoutRenderer.cs +++ b/src/Shared/LayoutRenderers/AspNetItemValueLayoutRenderer.cs @@ -36,6 +36,8 @@ namespace NLog.Web.LayoutRenderers [LayoutRenderer("aspnet-item")] public class AspNetItemValueLayoutRenderer : AspNetLayoutRendererBase { + private readonly NLog.LayoutRenderers.Wrappers.ObjectPathRendererWrapper _objectPathRenderer = new NLog.LayoutRenderers.Wrappers.ObjectPathRendererWrapper(); + /// /// Gets or sets the item variable name. /// @@ -53,7 +55,7 @@ public class AspNetItemValueLayoutRenderer : AspNetLayoutRendererBase /// This will emit the First Name property of the object in HttpContext.Items woith the key of 'person' in the collection /// /// - public string ObjectPath { get; set; } + public string ObjectPath { get => _objectPathRenderer.ObjectPath; set => _objectPathRenderer.ObjectPath = value; } /// /// Gets or sets the item variable name. @@ -67,6 +69,7 @@ public class AspNetItemValueLayoutRenderer : AspNetLayoutRendererBase /// invoked since ObjectPath is set /// /// + [Obsolete("Instead use ObjectPath. Marked obsolete with NLog.Web 5.2")] public bool EvaluateAsNestedProperties { get; set; } /// @@ -84,24 +87,36 @@ public class AspNetItemValueLayoutRenderer : AspNetLayoutRendererBase /// protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent) { - var context = HttpContextAccessor.HttpContext; + var item = Item; + if (string.IsNullOrEmpty(item)) + { + return; + } - if (Item == null) + var context = HttpContextAccessor.HttpContext; + if (context is null) { return; } object value = null; - // Function using the Item string as the object path - if (ObjectPath == null) + if (ObjectPath is null) { - value = PropertyReader.GetValue(Item, context?.Items, (items, key) => LookupItemValue(items, key), EvaluateAsNestedProperties); +#pragma warning disable CS0618 // Type or member is obsolete + value = PropertyReader.GetValue(item, context?.Items, (items, key) => LookupItemValue(items, key), EvaluateAsNestedProperties); +#pragma warning restore CS0618 // Type or member is obsolete + if (value is null) + return; } - // Function using the ObjectPath as the object path, hard code evaluateNestedProperties argument to true else { - value = PropertyReader.GetValue(Item, context?.Items, (items, key) => LookupItemValue(items, key), ObjectPath); + value = LookupItemValue(context?.Items, item); + if (value is null) + return; + + if (!_objectPathRenderer.TryGetPropertyValue(value, out value)) + return; } var formatProvider = GetFormatProvider(logEvent, Culture); diff --git a/src/Shared/LayoutRenderers/AspNetSessionValueLayoutRenderer.cs b/src/Shared/LayoutRenderers/AspNetSessionValueLayoutRenderer.cs index 4ba9f59d..8bbbd077 100644 --- a/src/Shared/LayoutRenderers/AspNetSessionValueLayoutRenderer.cs +++ b/src/Shared/LayoutRenderers/AspNetSessionValueLayoutRenderer.cs @@ -42,6 +42,8 @@ namespace NLog.Web.LayoutRenderers [LayoutRenderer("aspnet-session")] public class AspNetSessionValueLayoutRenderer : AspNetLayoutRendererBase { + private readonly NLog.LayoutRenderers.Wrappers.ObjectPathRendererWrapper _objectPathRenderer = new NLog.LayoutRenderers.Wrappers.ObjectPathRendererWrapper(); + /// /// Gets or sets the session item name. /// @@ -56,10 +58,16 @@ public class AspNetSessionValueLayoutRenderer : AspNetLayoutRendererBase /// public string Variable { get => Item; set => Item = value; } + /// + /// Gets or sets the object-property-navigation-path for lookup of nested property + /// + public string ObjectPath { get => _objectPathRenderer.ObjectPath; set => _objectPathRenderer.ObjectPath = value; } + /// /// Gets or sets whether variables with a dot are evaluated as properties or not /// /// + [Obsolete("Instead use ObjectPath. Marked obsolete with NLog.Web 5.2")] public bool EvaluateAsNestedProperties { get; set; } /// @@ -99,13 +107,13 @@ public SessionValueType ValueType protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent) { var item = Item; - if (item == null) + if (string.IsNullOrEmpty(item)) { return; } var context = HttpContextAccessor.HttpContext; - if (context == null) + if (context is null) { return; } @@ -131,12 +139,28 @@ protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent) return; } - var value = PropertyReader.GetValue(item, contextSession, _sessionValueLookup, EvaluateAsNestedProperties); - if (value != null) + object value = null; + + if (ObjectPath is null) { - var formatProvider = GetFormatProvider(logEvent, Culture); - builder.AppendFormattedValue(value, Format, formatProvider, ValueFormatter); +#pragma warning disable CS0618 // Type or member is obsolete + value = PropertyReader.GetValue(item, contextSession, _sessionValueLookup, EvaluateAsNestedProperties); +#pragma warning restore CS0618 // Type or member is obsolete + if (value is null) + return; } + else + { + value = _sessionValueLookup(contextSession, item); + if (value is null) + return; + + if (!_objectPathRenderer.TryGetPropertyValue(value, out value)) + return; + } + + var formatProvider = GetFormatProvider(logEvent, Culture); + builder.AppendFormattedValue(value, Format, formatProvider, ValueFormatter); } } diff --git a/tests/Shared/LayoutRenderers/AspNetItemValueLayoutRendererTests.cs b/tests/Shared/LayoutRenderers/AspNetItemValueLayoutRendererTests.cs index 4cf62ccd..3314ad78 100644 --- a/tests/Shared/LayoutRenderers/AspNetItemValueLayoutRendererTests.cs +++ b/tests/Shared/LayoutRenderers/AspNetItemValueLayoutRendererTests.cs @@ -113,7 +113,9 @@ public void NestedPropertyRendersValueItem(string itemKey, string variable, obje #endif var culture = CultureInfo.CurrentUICulture; renderer.Variable = variable; +#pragma warning disable CS0618 // Type or member is obsolete renderer.EvaluateAsNestedProperties = true; +#pragma warning restore CS0618 // Type or member is obsolete renderer.Culture = culture; // Act @@ -138,7 +140,9 @@ public void NestedPropertyRendersValueObjectPath(string itemKey, string variable #endif var culture = CultureInfo.CurrentUICulture; renderer.Variable = variable; +#pragma warning disable CS0618 // Type or member is obsolete renderer.EvaluateAsNestedProperties = true; +#pragma warning restore CS0618 // Type or member is obsolete renderer.Culture = culture; // Act @@ -209,7 +213,9 @@ public void NestedItemRendersProperly() #endif renderer.Item = "person.Name.First"; +#pragma warning disable CS0618 // Type or member is obsolete renderer.EvaluateAsNestedProperties = true; +#pragma warning restore CS0618 // Type or member is obsolete // Act string result = renderer.Render(new LogEventInfo()); @@ -247,7 +253,9 @@ public void NestedObjectPathRendersProperly() renderer.Item = "person"; renderer.ObjectPath = "Name.Last"; +#pragma warning disable CS0618 // Type or member is obsolete renderer.EvaluateAsNestedProperties = false; +#pragma warning restore CS0618 // Type or member is obsolete // Act string result = renderer.Render(new LogEventInfo()); @@ -284,8 +292,6 @@ public void NestedObjectPathRendersProperlyII() renderer.Item = "person"; renderer.ObjectPath = "Name.Last"; - renderer.EvaluateAsNestedProperties = false; - // Act string result = renderer.Render(new LogEventInfo()); diff --git a/tests/Shared/LayoutRenderers/AspNetSessionValueLayoutRendererTests.cs b/tests/Shared/LayoutRenderers/AspNetSessionValueLayoutRendererTests.cs index d3c5abaf..93b25515 100644 --- a/tests/Shared/LayoutRenderers/AspNetSessionValueLayoutRendererTests.cs +++ b/tests/Shared/LayoutRenderers/AspNetSessionValueLayoutRendererTests.cs @@ -52,7 +52,23 @@ public void NestedProps() var appSettingLayoutRenderer = new AspNetSessionValueLayoutRenderer() { Variable = "a.b", +#pragma warning disable CS0618 // Type or member is obsolete EvaluateAsNestedProperties = true +#pragma warning restore CS0618 // Type or member is obsolete + }; + + var o = new { b = "c" }; + //set in "a" + ExecTest("a", o, "c", appSettingLayoutRenderer); + } + + [Fact] + public void NestedPropsObjectPath() + { + var appSettingLayoutRenderer = new AspNetSessionValueLayoutRenderer() + { + Variable = "a", + ObjectPath = "b", }; var o = new { b = "c" }; @@ -66,7 +82,23 @@ public void NestedProps2() var appSettingLayoutRenderer = new AspNetSessionValueLayoutRenderer() { Variable = "a.b.c", +#pragma warning disable CS0618 // Type or member is obsolete EvaluateAsNestedProperties = true +#pragma warning restore CS0618 // Type or member is obsolete + }; + + var o = new { b = "c" }; + //set in "a" + ExecTest("a", o, "", appSettingLayoutRenderer); + } + + [Fact] + public void NestedPropsObjectPath2() + { + var appSettingLayoutRenderer = new AspNetSessionValueLayoutRenderer() + { + Variable = "a", + ObjectPath = "b.c" }; var o = new { b = "c" }; @@ -80,7 +112,9 @@ public void NestedProps3() var appSettingLayoutRenderer = new AspNetSessionValueLayoutRenderer() { Variable = "a.b..c", +#pragma warning disable CS0618 // Type or member is obsolete EvaluateAsNestedProperties = true +#pragma warning restore CS0618 // Type or member is obsolete }; var o = new { b = "c" }; @@ -94,7 +128,9 @@ public void EmptyPath() var appSettingLayoutRenderer = new AspNetSessionValueLayoutRenderer() { Variable = "", +#pragma warning disable CS0618 // Type or member is obsolete EvaluateAsNestedProperties = true +#pragma warning restore CS0618 // Type or member is obsolete }; var o = new { b = "c" }; @@ -108,7 +144,9 @@ public void EmptyVarname() var appSettingLayoutRenderer = new AspNetSessionValueLayoutRenderer() { Variable = "", - EvaluateAsNestedProperties = false +#pragma warning disable CS0618 // Type or member is obsolete + EvaluateAsNestedProperties = true +#pragma warning restore CS0618 // Type or member is obsolete }; var o = new { b = "c" };