[automated] Merge branch 'main' => 'dev' (#5461)

This commit is contained in:
Igor Velikorossov 2024-10-01 20:23:31 +10:00 коммит произвёл GitHub
Родитель 910070c2d2 985641c2f3
Коммит 39383ee9da
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
10 изменённых файлов: 158 добавлений и 15 удалений

Просмотреть файл

@ -20,7 +20,9 @@ internal sealed class RequestMessageSnapshotStrategy : ResilienceStrategy
ResilienceContext context,
TState state)
{
if (!context.Properties.TryGetValue(ResilienceKeys.RequestMessage, out var request) || request is null)
HttpRequestMessage? request = context.GetRequestMessage();
if (request is null)
{
Throw.InvalidOperationException("The HTTP request message was not found in the resilience context.");
}

Просмотреть файл

@ -94,7 +94,7 @@ public static partial class ResilienceHttpClientBuilderExtensions
requestMessage.SetResilienceContext(args.ActionContext);
// replace the request message
args.ActionContext.Properties.Set(ResilienceKeys.RequestMessage, requestMessage);
args.ActionContext.SetRequestMessage(requestMessage);
if (args.PrimaryContext.Properties.TryGetValue(ResilienceKeys.RoutingStrategy, out var routingPipeline))
{

Просмотреть файл

@ -10,7 +10,7 @@ namespace Microsoft.Extensions.Http.Resilience.Internal;
internal static class ResilienceKeys
{
public static readonly ResiliencePropertyKey<HttpRequestMessage> RequestMessage = new("Resilience.Http.RequestMessage");
public static readonly ResiliencePropertyKey<HttpRequestMessage?> RequestMessage = new("Resilience.Http.RequestMessage");
public static readonly ResiliencePropertyKey<RequestRoutingStrategy> RoutingStrategy = new("Resilience.Http.RequestRoutingStrategy");

Просмотреть файл

@ -0,0 +1,46 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
using Microsoft.Extensions.Http.Resilience.Internal;
using Microsoft.Shared.DiagnosticIds;
using Microsoft.Shared.Diagnostics;
using Polly;
namespace Polly;
/// <summary>
/// Provides utility methods for working with <see cref="ResilienceContext"/>.
/// </summary>
[Experimental(diagnosticId: DiagnosticIds.Experiments.Resilience, UrlFormat = DiagnosticIds.UrlFormat)]
public static class HttpResilienceContextExtensions
{
/// <summary>
/// Gets the request message from the <see cref="ResilienceContext"/>.
/// </summary>
/// <param name="context">The resilience context.</param>
/// <returns>
/// The request message.
/// If the request message is not present in the <see cref="ResilienceContext"/> the method returns <see langword="null"/>.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="context"/> is <see langword="null"/>.</exception>
public static HttpRequestMessage? GetRequestMessage(this ResilienceContext context)
{
_ = Throw.IfNull(context);
return context.Properties.GetValue(ResilienceKeys.RequestMessage, default);
}
/// <summary>
/// Sets the request message on the <see cref="ResilienceContext"/>.
/// </summary>
/// <param name="context">The resilience context.</param>
/// <param name="requestMessage">The request message.</param>
/// <exception cref="ArgumentNullException"><paramref name="context"/> is <see langword="null"/>.</exception>
public static void SetRequestMessage(this ResilienceContext context, HttpRequestMessage? requestMessage)
{
_ = Throw.IfNull(context);
context.Properties.Set(ResilienceKeys.RequestMessage, requestMessage);
}
}

Просмотреть файл

@ -58,7 +58,7 @@ public class ResilienceHandler : DelegatingHandler
ResilienceContext context = GetOrSetResilienceContext(request, cancellationToken, out bool created);
TrySetRequestMetadata(context, request);
SetRequestMessage(context, request);
context.SetRequestMessage(request);
try
{
@ -117,7 +117,7 @@ public class ResilienceHandler : DelegatingHandler
ResilienceContext context = GetOrSetResilienceContext(request, cancellationToken, out bool created);
TrySetRequestMetadata(context, request);
SetRequestMessage(context, request);
context.SetRequestMessage(request);
try
{
@ -165,11 +165,8 @@ public class ResilienceHandler : DelegatingHandler
}
}
private static void SetRequestMessage(ResilienceContext context, HttpRequestMessage request)
=> context.Properties.Set(ResilienceKeys.RequestMessage, request);
private static HttpRequestMessage GetRequestMessage(ResilienceContext context, HttpRequestMessage request)
=> context.Properties.GetValue(ResilienceKeys.RequestMessage, request);
=> context.GetRequestMessage() ?? request;
private static void RestoreResilienceContext(ResilienceContext context, HttpRequestMessage request, bool created)
{

Просмотреть файл

@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Http.Resilience.Internal;
using Microsoft.Shared.Diagnostics;
@ -26,7 +27,9 @@ internal sealed class RoutingResilienceStrategy : ResilienceStrategy
ResilienceContext context,
TState state)
{
if (!context.Properties.TryGetValue(ResilienceKeys.RequestMessage, out var request))
HttpRequestMessage? request = context.GetRequestMessage();
if (request is null)
{
Throw.InvalidOperationException("The HTTP request message was not found in the resilience context.");
}

Просмотреть файл

@ -20,7 +20,7 @@ public class RequestMessageSnapshotStrategyTests
var strategy = Create();
var context = ResilienceContextPool.Shared.Get();
using var request = new HttpRequestMessage();
context.Properties.Set(ResilienceKeys.RequestMessage, request);
context.SetRequestMessage(request);
using var response = await strategy.ExecuteAsync(
context =>
@ -39,5 +39,15 @@ public class RequestMessageSnapshotStrategyTests
strategy.Invoking(s => s.Execute(() => { })).Should().Throw<InvalidOperationException>();
}
[Fact]
public void ExecuteAsync_RequestMessageIsNull_Throws()
{
var strategy = Create();
var context = ResilienceContextPool.Shared.Get();
context.SetRequestMessage(null);
strategy.Invoking(s => s.Execute(_ => { }, context)).Should().Throw<InvalidOperationException>();
}
private static ResiliencePipeline Create() => new ResiliencePipelineBuilder().AddStrategy(_ => new RequestMessageSnapshotStrategy(), Mock.Of<ResilienceStrategyOptions>()).Build();
}

Просмотреть файл

@ -0,0 +1,77 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Net.Http;
using Microsoft.Extensions.Http.Resilience.Internal;
using Polly;
using Xunit;
namespace Microsoft.Extensions.Http.Resilience.Test.Resilience;
public class HttpResilienceContextExtensionsTests
{
[Fact]
public void GetRequestMessage_ResilienceContextIsNull_Throws()
{
ResilienceContext context = null!;
Assert.Throws<ArgumentNullException>(context.GetRequestMessage);
}
[Fact]
public void GetRequestMessage_RequestMessageIsMissing_ReturnsNull()
{
var context = ResilienceContextPool.Shared.Get();
Assert.Null(context.GetRequestMessage());
}
[Fact]
public void GetRequestMessage_RequestMessageIsNull_ReturnsNull()
{
var context = ResilienceContextPool.Shared.Get();
context.Properties.Set(ResilienceKeys.RequestMessage, null);
Assert.Null(context.GetRequestMessage());
}
[Fact]
public void GetRequestMessage_RequestMessageIsPresent_ReturnsRequestMessage()
{
var context = ResilienceContextPool.Shared.Get();
using var request = new HttpRequestMessage();
context.Properties.Set(ResilienceKeys.RequestMessage, request);
Assert.Same(request, context.GetRequestMessage());
}
[Fact]
public void SetRequestMessage_ResilienceContextIsNull_Throws()
{
ResilienceContext context = null!;
using var request = new HttpRequestMessage();
Assert.Throws<ArgumentNullException>(() => context.SetRequestMessage(request));
}
[Fact]
public void SetRequestMessage_RequestMessageIsNull_SetsNullRequestMessage()
{
var context = ResilienceContextPool.Shared.Get();
context.SetRequestMessage(null);
Assert.True(context.Properties.TryGetValue(ResilienceKeys.RequestMessage, out HttpRequestMessage? request));
Assert.Null(request);
}
[Fact]
public void SetRequestMessage_RequestMessageIsNotNull_SetsRequestMessage()
{
var context = ResilienceContextPool.Shared.Get();
using var request = new HttpRequestMessage();
context.SetRequestMessage(request);
Assert.True(context.Properties.TryGetValue(ResilienceKeys.RequestMessage, out HttpRequestMessage? actualRequest));
Assert.Same(request, actualRequest);
}
}

Просмотреть файл

@ -8,7 +8,6 @@ using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.Extensions.Http.Diagnostics;
using Microsoft.Extensions.Http.Resilience.Internal;
using Microsoft.Extensions.Http.Resilience.Test.Helpers;
using Polly;
using Xunit;
@ -108,7 +107,7 @@ public class ResilienceHandlerTest
handler.InnerHandler = new TestHandlerStub((r, _) =>
{
r.GetResilienceContext().Should().NotBeNull();
r.GetResilienceContext()!.Properties.GetValue(ResilienceKeys.RequestMessage, null!).Should().BeSameAs(r);
r.GetResilienceContext()!.GetRequestMessage().Should().BeSameAs(r);
return Task.FromResult(new HttpResponseMessage { StatusCode = HttpStatusCode.Created });
});

Просмотреть файл

@ -4,7 +4,6 @@
using System;
using System.Net.Http;
using FluentAssertions;
using Microsoft.Extensions.Http.Resilience.Internal;
using Microsoft.Extensions.Http.Resilience.Routing.Internal;
using Moq;
using Polly;
@ -22,6 +21,16 @@ public class RoutingResilienceStrategyTests
strategy.Invoking(s => s.Execute(() => { })).Should().Throw<InvalidOperationException>().WithMessage("The HTTP request message was not found in the resilience context.");
}
[Fact]
public void RequestMessageIsNull_Throws()
{
var strategy = Create(() => Mock.Of<RequestRoutingStrategy>());
var context = ResilienceContextPool.Shared.Get();
context.SetRequestMessage(null);
strategy.Invoking(s => s.Execute(_ => { }, context)).Should().Throw<InvalidOperationException>().WithMessage("The HTTP request message was not found in the resilience context.");
}
[Fact]
public void NoRoutingProvider_Ok()
{
@ -29,7 +38,7 @@ public class RoutingResilienceStrategyTests
var strategy = Create(null);
var context = ResilienceContextPool.Shared.Get();
context.Properties.Set(ResilienceKeys.RequestMessage, request);
context.SetRequestMessage(request);
strategy.Invoking(s => s.Execute(_ => { }, context)).Should().NotThrow();
}