Skip to content

Commit

Permalink
Added Layout renderer for ASP.NET Request route parameters (#740)
Browse files Browse the repository at this point in the history
* Added Layout renderer for ASP.NET Request route parameters

* Added unit tests of AspNetRequestRouteParametersRenderer
  • Loading branch information
ThomasArdal authored Dec 3, 2021
1 parent 0294fd7 commit ecac594
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 0 deletions.
87 changes: 87 additions & 0 deletions src/Shared/LayoutRenderers/AspNetRequestRouteParametersRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System.Text;
using NLog.LayoutRenderers;
using System.Collections.Generic;
using System.Linq;
#if !ASP_NET_CORE
using System.Web.Routing;
#else
using Microsoft.AspNetCore.Routing;
#endif

namespace NLog.Web.LayoutRenderers
{
/// <summary>
/// ASP.NET Request Route Parameters
/// </summary>
/// <example>
/// <para>Example usage of ${aspnet-request-routeparameters}:</para>
/// <code lang="NLog Layout Renderer">
/// ${aspnet-request-routeparameters:OutputFormat=Flat}
/// ${aspnet-request-routeparameters:OutputFormat=JsonArray}
/// ${aspnet-request-routeparameters:OutputFormat=JsonDictionary}
/// </code>
/// </example>
[LayoutRenderer("aspnet-request-routeparameters")]
public class AspNetRequestRouteParametersRenderer : AspNetLayoutMultiValueRendererBase
{
/// <summary>
/// List Route Parameter' Key to be rendered from Request.
/// If empty, then render all parameters
/// </summary>
public List<string> RouteParameterKeys { get; set; }

/// <summary>
/// Renders the specified ASP.NET Route Parameters and appends it to the specified <see cref="StringBuilder" />.
/// </summary>
/// <param name="builder"></param>
/// <param name="logEvent"></param>
protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
{
var context = HttpContextAccessor.HttpContext;
if (context == null)
{
return;
}

#if !ASP_NET_CORE
RouteValueDictionary routeParameters = RouteTable.Routes?.GetRouteData(context)?.Values;
#else
RouteValueDictionary routeParameters = context.GetRouteData()?.Values;
#endif

bool printAllRouteParameter = RouteParameterKeys == null || RouteParameterKeys.Count == 0;
List<string> routeParameterKeys = RouteParameterKeys;
if (routeParameters == null || routeParameters.Count == 0)
{
return;
}

if (printAllRouteParameter)
{
routeParameterKeys = routeParameters.Keys.ToList();
}

IEnumerable<KeyValuePair<string, string>> pairs = GetPairs(routeParameters, routeParameterKeys);
SerializePairs(pairs, builder, logEvent);
}

private static IEnumerable<KeyValuePair<string, string>> GetPairs(RouteValueDictionary routeParameters, List<string> routeParameterKeys)
{
foreach (string key in routeParameterKeys)
{
// This platform specific code is to prevent an unncessary .ToString call otherwise.

if (!routeParameters.TryGetValue(key, out object objValue))
{
continue;
}

string value = objValue.ToString();
if (!string.IsNullOrEmpty(value))
{
yield return new KeyValuePair<string, string>(key, value);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using NLog.Web.LayoutRenderers;
using NLog.Web.Enums;
using Xunit;
using System.Collections.Specialized;
using NSubstitute;
#if ASP_NET_CORE
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing;
#endif

namespace NLog.Web.Tests.LayoutRenderers
{
public class AspNetRequestRouteParametersRendererTests : LayoutRenderersTestBase<AspNetRequestRouteParametersRenderer>
{
[Fact]
public void NullRouteParametersRenderersEmptyString()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();

AddRoutingFeature(httpContext);

// Act
string result = renderer.Render(LogEventInfo.CreateNullEvent());

// Assert
Assert.Empty(result);
}

#if ASP_NET_CORE
[Fact]
public void NullKeyRendersAllRouteParameters()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();
renderer.RouteParameterKeys = null;

SetupRouteParameters(httpContext);

// Act
string result = renderer.Render(LogEventInfo.CreateNullEvent());

// Assert
Assert.Equal("key1=value1,key2=value2", result);
}

[Fact]
public void SingleKeyRendersRouteParameter()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();
renderer.RouteParameterKeys = new List<string> { "key2" };

SetupRouteParameters(httpContext);

// Act
string result = renderer.Render(LogEventInfo.CreateNullEvent());

// Assert
Assert.Equal("key2=value2", result);
}

private void SetupRouteParameters(HttpContext httpContext)
{
var routeData = new RouteData();
var routingFeature = Substitute.For<IRoutingFeature>();
var collection = new FeatureCollection();
collection.Set(routingFeature);
httpContext.Features.Returns(collection);

routeData.Values.Add("key1", "value1");
routeData.Values.Add("key2", "value2");
routingFeature.RouteData.Returns(routeData);
}
#endif
}
}

0 comments on commit ecac594

Please sign in to comment.