diff --git a/src/Http/Http.Abstractions/src/Internal/ParsingHelpers.cs b/src/Http/Http.Abstractions/src/Internal/ParsingHelpers.cs index 971447fa44..60c3197e3c 100644 --- a/src/Http/Http.Abstractions/src/Internal/ParsingHelpers.cs +++ b/src/Http/Http.Abstractions/src/Internal/ParsingHelpers.cs @@ -19,11 +19,9 @@ namespace Microsoft.AspNetCore.Http.Internal public static StringValues GetHeaderSplit(IHeaderDictionary headers, string key) { var values = GetHeaderUnmodified(headers, key); - return new StringValues(GetHeaderSplitImplementation(values).ToArray()); - } - private static IEnumerable GetHeaderSplitImplementation(StringValues values) - { + StringValues result = default; + foreach (var segment in new HeaderSegmentCollection(values)) { if (!StringSegment.IsNullOrEmpty(segment.Data)) @@ -31,10 +29,12 @@ namespace Microsoft.AspNetCore.Http.Internal var value = DeQuote(segment.Data.Value); if (!string.IsNullOrEmpty(value)) { - yield return value; + result = StringValues.Concat(in result, value); } } } + + return result; } public static StringValues GetHeaderUnmodified(IHeaderDictionary headers, string key) diff --git a/src/Http/perf/Microbenchmarks/AssemblyInfo.cs b/src/Http/perf/Microbenchmarks/AssemblyInfo.cs new file mode 100644 index 0000000000..32248e0d1b --- /dev/null +++ b/src/Http/perf/Microbenchmarks/AssemblyInfo.cs @@ -0,0 +1 @@ +[assembly: BenchmarkDotNet.Attributes.AspNetCoreBenchmark] diff --git a/src/Http/perf/Microbenchmarks/GetHeaderSplitBenchmark.cs b/src/Http/perf/Microbenchmarks/GetHeaderSplitBenchmark.cs new file mode 100644 index 0000000000..9105b5c448 --- /dev/null +++ b/src/Http/perf/Microbenchmarks/GetHeaderSplitBenchmark.cs @@ -0,0 +1,63 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Configs; +using Microsoft.AspNetCore.Http.Internal; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.AspNetCore.Http.Abstractions.Microbenchmarks +{ + public class GetHeaderSplitBenchmark + { + HeaderDictionary _dictionary; + + [GlobalSetup] + public void GlobalSetup() + { + var dict = new Dictionary() + { + { "singleValue", new StringValues("single") }, + { "singleValueQuoted", new StringValues("\"single\"") }, + { "doubleValue", new StringValues(new [] { "first", "second" }) }, + { "manyValue", new StringValues(new [] { "first", "second", "third", "fourth", "fifth", "sixth" }) } + }; + _dictionary = new HeaderDictionary(dict); + } + + [Benchmark] + public void SplitSingleHeader() + { + var values = ParsingHelpers.GetHeaderSplit(_dictionary, "singleValue"); + if (values.Count != 1) + throw new Exception(); + } + + [Benchmark] + public void SplitSingleQuotedHeader() + { + var values = ParsingHelpers.GetHeaderSplit(_dictionary, "singleValueQuoted"); + if (values.Count != 1) + throw new Exception(); + } + + [Benchmark] + public void SplitDoubleHeader() + { + var values = ParsingHelpers.GetHeaderSplit(_dictionary, "doubleValue"); + if (values.Count != 2) + throw new Exception(); + } + + [Benchmark] + public void SplitManyHeaders() + { + var values = ParsingHelpers.GetHeaderSplit(_dictionary, "manyValue"); + if (values.Count != 6) + throw new Exception(); + } + } +} diff --git a/src/Http/perf/Microbenchmarks/Microsoft.AspNetCore.Http.Microbenchmarks.csproj b/src/Http/perf/Microbenchmarks/Microsoft.AspNetCore.Http.Microbenchmarks.csproj new file mode 100644 index 0000000000..7a31f1da5b --- /dev/null +++ b/src/Http/perf/Microbenchmarks/Microsoft.AspNetCore.Http.Microbenchmarks.csproj @@ -0,0 +1,14 @@ + + + + Exe + netcoreapp3.0 + + + + + + + + +