Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some performance improvements in Azure.Core for .Net 6.0 #32481

Merged
merged 7 commits into from
Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 64 additions & 2 deletions sdk/core/Azure.Core/src/Pipeline/HttpClientTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,25 +207,61 @@ private static HttpRequestMessage BuildRequestMessage(HttpMessage message)

internal static bool TryGetHeader(HttpHeaders headers, HttpContent? content, string name, [NotNullWhen(true)] out string? value)
{
#if NET6_0_OR_GREATER
if (headers.NonValidated.TryGetValues(name, out HeaderStringValues values) ||
content is not null && content.Headers.NonValidated.TryGetValues(name, out values))
{
value = JoinHeaderValues(values);
return true;
}
#else
if (TryGetHeader(headers, content, name, out IEnumerable<string>? values))
{
value = JoinHeaderValues(values);
return true;
}

#endif
value = null;
return false;
}

internal static bool TryGetHeader(HttpHeaders headers, HttpContent? content, string name, [NotNullWhen(true)] out IEnumerable<string>? values)
{
#if NET6_0_OR_GREATER
if (headers.NonValidated.TryGetValues(name, out HeaderStringValues headerStringValues) ||
content != null &&
content.Headers.NonValidated.TryGetValues(name, out headerStringValues))
{
values = headerStringValues;
return true;
}

values = null;
return false;
#else
return headers.TryGetValues(name, out values) ||
content != null &&
content.Headers.TryGetValues(name, out values);
#endif

}

internal static IEnumerable<HttpHeader> GetHeaders(HttpHeaders headers, HttpContent? content)
{
#if NET6_0_OR_GREATER
foreach (var (key, value) in headers.NonValidated)
{
yield return new HttpHeader(key, JoinHeaderValues(value));
}

if (content is not null)
{
foreach (var (key, value) in content.Headers.NonValidated)
{
yield return new HttpHeader(key, JoinHeaderValues(value));
}
}
#else
foreach (KeyValuePair<string, IEnumerable<string>> header in headers)
{
yield return new HttpHeader(header.Key, JoinHeaderValues(header.Value));
Expand All @@ -238,28 +274,43 @@ internal static IEnumerable<HttpHeader> GetHeaders(HttpHeaders headers, HttpCont
yield return new HttpHeader(header.Key, JoinHeaderValues(header.Value));
}
}
#endif

}

internal static bool RemoveHeader(HttpHeaders headers, HttpContent? content, string name)
{
// .Remove throws on invalid header name so use TryGet here to check
#if NET6_0_OR_GREATER
if (headers.NonValidated.Contains(name) && headers.Remove(name))
{
return true;
}

return content is not null && content.Headers.NonValidated.Contains(name) && content.Headers.Remove(name);
#else
if (headers.TryGetValues(name, out _) && headers.Remove(name))
{
return true;
}

return content?.Headers.TryGetValues(name, out _) == true && content.Headers.Remove(name);
#endif
}

internal static bool ContainsHeader(HttpHeaders headers, HttpContent? content, string name)
{
// .Contains throws on invalid header name so use TryGet here
#if NET6_0_OR_GREATER
return headers.NonValidated.Contains(name) || content is not null && content.Headers.NonValidated.Contains(name);
#else
if (headers.TryGetValues(name, out _))
{
return true;
}

return content?.Headers.TryGetValues(name, out _) == true;
#endif
}

internal static void CopyHeaders(HttpHeaders from, HttpHeaders to)
Expand All @@ -272,11 +323,22 @@ internal static void CopyHeaders(HttpHeaders from, HttpHeaders to)
}
}
}

#if NET6_0_OR_GREATER
private static string JoinHeaderValues(HeaderStringValues values)
{
return values.Count switch
{
0 => string.Empty,
1 => values.ToString(),
_ => string.Join(",", values)
};
}
#else
private static string JoinHeaderValues(IEnumerable<string> values)
{
return string.Join(",", values);
}
#endif

private sealed class PipelineRequest : Request
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,21 @@ public override void Process(HttpMessage message, ReadOnlyMemory<HttpPipelinePol
/// <inheritdoc />
public override ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory<HttpPipelinePolicy> pipeline)
{
async ValueTask ProcessAsyncInner(HttpMessage message, ReadOnlyMemory<HttpPipelinePolicy> pipeline)
{
OnSendingRequest(message);
await ProcessNextAsync(message, pipeline).ConfigureAwait(false);
OnReceivedResponse(message);
}

if (!_hasOnReceivedResponse)
{
// If OnReceivedResponse was not overridden we can avoid creating a state machine and return the task directly
OnSendingRequest(message);
return ProcessNextAsync(message, pipeline);
}

return ProcessAsyncInner(message, pipeline);
return InnerProcessAsync(message, pipeline);
}

private async ValueTask InnerProcessAsync(HttpMessage message, ReadOnlyMemory<HttpPipelinePolicy> pipeline)
{
OnSendingRequest(message);
await ProcessNextAsync(message, pipeline).ConfigureAwait(false);
OnReceivedResponse(message);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(RequiredTargetFrameworks)</TargetFrameworks>
<TargetFrameworks>$(RequiredTargetFrameworks);net6.0</TargetFrameworks>
<!-- Remove this line when Azure.Core is released for net6.0 -->
<RunApiCompat Condition="'$(TargetFramework)' == 'net6.0'">false</RunApiCompat>
</PropertyGroup>
<PropertyGroup>
<AssemblyTitle>Microsoft Azure.Storage.Common client library</AssemblyTitle>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,14 @@ public void SetAccountKey(string accountKey) =>
/// </summary>
/// <param name="message">The message to sign.</param>
/// <returns>The signed message.</returns>
internal string ComputeHMACSHA256(string message) =>
Convert.ToBase64String(new HMACSHA256(AccountKeyValue).ComputeHash(Encoding.UTF8.GetBytes(message)));
internal string ComputeHMACSHA256(string message)
{
#if NET6_0_OR_GREATER
return Convert.ToBase64String(HMACSHA256.HashData(AccountKeyValue, Encoding.UTF8.GetBytes(message)));
#else
return Convert.ToBase64String(new HMACSHA256(AccountKeyValue).ComputeHash(Encoding.UTF8.GetBytes(message)));
#endif
}

/// <summary>
/// Generates a base-64 hash signature string for an HTTP request or
Expand Down