From baa143aa27f37cbb0917ccccb2aa678bce7e68fa Mon Sep 17 00:00:00 2001 From: Paulo Morgado <470455+paulomorgado@users.noreply.github.com> Date: Wed, 8 May 2024 20:19:12 +0100 Subject: [PATCH 1/3] Optimized string concatenation with `string.Create` Replaced `StringBuilder` concatenation with the more efficient `string.Create` method for creating new strings by concatenating `scheme`, `host`, `pathBase`, `path`, and `queryString`. This method reduces overhead by avoiding multiple string concatenations and allocating the correct buffer size for the new string. The `CopyTo` method is used in a callback function to copy each string to the new string, slicing the buffer to remove the copied part. The `SchemeDelimiter` is always copied to the new string, regardless of its length. This change enhances the performance of the code. --- src/Http/Http.Extensions/src/UriHelper.cs | 49 ++++++++++++++++++----- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/Http/Http.Extensions/src/UriHelper.cs b/src/Http/Http.Extensions/src/UriHelper.cs index 6c98c4d4890b..097b388d07be 100644 --- a/src/Http/Http.Extensions/src/UriHelper.cs +++ b/src/Http/Http.Extensions/src/UriHelper.cs @@ -4,7 +4,6 @@ using System.Buffers; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; -using System.Text; namespace Microsoft.AspNetCore.Http.Extensions; @@ -210,18 +209,48 @@ public static string GetDisplayUrl(this HttpRequest request) var path = request.Path.Value ?? string.Empty; var queryString = request.QueryString.Value ?? string.Empty; - // PERF: Calculate string length to allocate correct buffer size for StringBuilder. var length = scheme.Length + SchemeDelimiter.Length + host.Length + pathBase.Length + path.Length + queryString.Length; - return new StringBuilder(length) - .Append(scheme) - .Append(SchemeDelimiter) - .Append(host) - .Append(pathBase) - .Append(path) - .Append(queryString) - .ToString(); + return string.Create( + length, + (scheme, host, pathBase, path, queryString), + static (buffer, uriParts) => + { + var (scheme, host, pathBase, path, queryString) = uriParts; + + if (scheme.Length > 0) + { + scheme.CopyTo(buffer); + buffer = buffer.Slice(scheme.Length); + } + + SchemeDelimiter.CopyTo(buffer); + buffer = buffer.Slice(SchemeDelimiter.Length); + + if (host.Length > 0) + { + host.CopyTo(buffer); + buffer = buffer.Slice(host.Length); + } + + if (pathBase.Length > 0) + { + pathBase.CopyTo(buffer); + buffer = buffer.Slice(pathBase.Length); + } + + if (path.Length > 0) + { + path.CopyTo(buffer); + buffer = buffer.Slice(path.Length); + } + + if (queryString.Length > 0) + { + queryString.CopyTo(buffer); + } + }); } /// From ea0ba89acbe6ea6b02e44207e143e640ceea8760 Mon Sep 17 00:00:00 2001 From: Paulo Morgado <470455+paulomorgado@users.noreply.github.com> Date: Mon, 17 Jun 2024 11:48:32 +0100 Subject: [PATCH 2/3] changed to string.Concat(params ReadOnlySpan) --- src/Http/Http.Extensions/src/UriHelper.cs | 49 +---------------------- 1 file changed, 1 insertion(+), 48 deletions(-) diff --git a/src/Http/Http.Extensions/src/UriHelper.cs b/src/Http/Http.Extensions/src/UriHelper.cs index 097b388d07be..d281b37dd4e2 100644 --- a/src/Http/Http.Extensions/src/UriHelper.cs +++ b/src/Http/Http.Extensions/src/UriHelper.cs @@ -203,54 +203,7 @@ public static string GetEncodedPathAndQuery(this HttpRequest request) /// suitable only for display. public static string GetDisplayUrl(this HttpRequest request) { - var scheme = request.Scheme ?? string.Empty; - var host = request.Host.Value ?? string.Empty; - var pathBase = request.PathBase.Value ?? string.Empty; - var path = request.Path.Value ?? string.Empty; - var queryString = request.QueryString.Value ?? string.Empty; - - var length = scheme.Length + SchemeDelimiter.Length + host.Length - + pathBase.Length + path.Length + queryString.Length; - - return string.Create( - length, - (scheme, host, pathBase, path, queryString), - static (buffer, uriParts) => - { - var (scheme, host, pathBase, path, queryString) = uriParts; - - if (scheme.Length > 0) - { - scheme.CopyTo(buffer); - buffer = buffer.Slice(scheme.Length); - } - - SchemeDelimiter.CopyTo(buffer); - buffer = buffer.Slice(SchemeDelimiter.Length); - - if (host.Length > 0) - { - host.CopyTo(buffer); - buffer = buffer.Slice(host.Length); - } - - if (pathBase.Length > 0) - { - pathBase.CopyTo(buffer); - buffer = buffer.Slice(pathBase.Length); - } - - if (path.Length > 0) - { - path.CopyTo(buffer); - buffer = buffer.Slice(path.Length); - } - - if (queryString.Length > 0) - { - queryString.CopyTo(buffer); - } - }); + return string.Concat((ReadOnlySpan)[request.Scheme, SchemeDelimiter, request.Host.Value, request.PathBase.Value, request.Path.Value, request.QueryString.Value]); } /// From 3145a5f3b4254ecd24fab033d1048321233345f1 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Wed, 18 Dec 2024 18:40:11 -0800 Subject: [PATCH 3/3] Update src/Http/Http.Extensions/src/UriHelper.cs --- src/Http/Http.Extensions/src/UriHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Http.Extensions/src/UriHelper.cs b/src/Http/Http.Extensions/src/UriHelper.cs index d281b37dd4e2..fc951704a85e 100644 --- a/src/Http/Http.Extensions/src/UriHelper.cs +++ b/src/Http/Http.Extensions/src/UriHelper.cs @@ -203,7 +203,7 @@ public static string GetEncodedPathAndQuery(this HttpRequest request) /// suitable only for display. public static string GetDisplayUrl(this HttpRequest request) { - return string.Concat((ReadOnlySpan)[request.Scheme, SchemeDelimiter, request.Host.Value, request.PathBase.Value, request.Path.Value, request.QueryString.Value]); + return string.Concat([request.Scheme, SchemeDelimiter, request.Host.Value, request.PathBase.Value, request.Path.Value, request.QueryString.Value]); } ///