Difficulty using states to test retry logic #303

Closed
opened 2025-12-29 15:20:14 +01:00 by adam · 1 comment
Owner

Originally created by @jecjackal on GitHub (Oct 9, 2020).

Hi WireMock.Net team,

I built a very lightweight OAuth service, and I wish to call it from a second service. I decided to wrap my requests in a retry policy via Polly. The application code is shown below:

public Task<string> GetToken(string clientId,
                                     string clientSecret,
                                     string grantType,
                                     string scope)
        {
            KeyValuePair<string, string>[] postData = {
                new KeyValuePair<string,string>("client_id", clientId),
                new KeyValuePair<string,string>("client_secret", clientSecret),
                new KeyValuePair<string,string>("grant_type", grantType),
                new KeyValuePair<string,string>("scope", scope),
            };
            
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"http://{identityServiceHost}/connect/token");
            request.Content = new FormUrlEncodedContent(postData);
            request.Headers.Accept.TryParseAdd(MediaTypeNames.Application.Json);

            Policy<HttpResponseMessage> retryPolicy = Policy
                                                      // Handle any exceptions that may occur during the request.
                                                      .Handle<HttpRequestException >()
                                                      // Also consider any response that doesn't have a 200 status code to be a failure.
                                                      .OrResult<HttpResponseMessage>(r => r.StatusCode != HttpStatusCode.OK)
                                                      .WaitAndRetry(5,
                                                                    i => TimeSpan.FromMilliseconds(50),
                                                                    ((result,
                                                                      i) => logger.LogWarning($"Failed to call Pricing_Service", result)));

            return Task.Run(() =>
            {
                HttpResponseMessage responseMessage = retryPolicy.Execute(() =>
                {
                    var a = httpClient.SendAsync(request)
                                      .Result;
                    return a;
                });
                
                IdentityServiceResponse response =
                    JsonSerializer.Deserialize<IdentityServiceResponse>(responseMessage.Content.ReadAsStringAsync()
                                                                            .Result);
                return response.AccessToken;
            });
        }

I have setup the test below to stress the retry logic:

        private WireMockServer identityServerMock;

        [OneTimeSetUp]
        public void Before()
        {
            WireMockServerSettings settings = new WireMockServerSettings();
            settings.Urls = new[] {"http://+:9000"};
            identityServerMock = WireMockServer.Start(settings);
        }


        [OneTimeTearDown]
        public void After()
        {
            identityServerMock.Dispose();
        }


        [TearDown]
        public void AfterEach()
        {
            identityServerMock.Reset();
        }

        [Test]
        public void GetToken_Should_Retry_500_Errors()
        {
            IdentityServiceResponse response = new IdentityServiceResponse
            {
                AccessToken = "testus",
                ExpiresIn = 3600,
                TokenType = "Bearer",
                Scope = "scope"
            };

            const string scenario = "retry 500";
            const string state1 = "pass";
            const string state2 = "after pass";
            
            identityServerMock.Given(Request.Create().WithPath("/connect/token").UsingPost())
                              .InScenario(scenario)
                              .WillSetStateTo(state1)
                              .RespondWith(
                                           Response.Create()
                                                   .WithStatusCode(500));
            
            identityServerMock.Given(Request.Create().WithPath("/connect/token").UsingPost())
                              .InScenario(scenario)
                              .WhenStateIs(state1)
                              .WillSetStateTo(state2)
                              .RespondWith(
                                           Response.Create()
                                                   .WithStatusCode(200)
                                                   .WithBody(JsonSerializer.Serialize(response)));
            
            Mock<ILogger> loggerMock = new Mock<ILogger>();
            IIdentityService service = new IdentityService(loggerMock.Object,
                                                           new HttpClient(),
                                                           "localhost:9000");
            string token = service.GetToken("testus",
                                            "pass",
                                            "client_credentials",
                                            "scope").Result;

            Assert.That(token,
                        Is.EqualTo(response.AccessToken));
        }

Unfortunately, I am getting this error upon making the second call to /connect/token:
The request message was already sent. Cannot send the same request message multiple times.

Can someone help point me in the right direction? I believe I am not switching scenario states correctly, but I am not sure what I am doing incorrectly.

Thank you for your help,

Jec

Originally created by @jecjackal on GitHub (Oct 9, 2020). Hi WireMock.Net team, I built a very lightweight OAuth service, and I wish to call it from a second service. I decided to wrap my requests in a retry policy via Polly. The application code is shown below: ``` c# public Task<string> GetToken(string clientId, string clientSecret, string grantType, string scope) { KeyValuePair<string, string>[] postData = { new KeyValuePair<string,string>("client_id", clientId), new KeyValuePair<string,string>("client_secret", clientSecret), new KeyValuePair<string,string>("grant_type", grantType), new KeyValuePair<string,string>("scope", scope), }; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"http://{identityServiceHost}/connect/token"); request.Content = new FormUrlEncodedContent(postData); request.Headers.Accept.TryParseAdd(MediaTypeNames.Application.Json); Policy<HttpResponseMessage> retryPolicy = Policy // Handle any exceptions that may occur during the request. .Handle<HttpRequestException >() // Also consider any response that doesn't have a 200 status code to be a failure. .OrResult<HttpResponseMessage>(r => r.StatusCode != HttpStatusCode.OK) .WaitAndRetry(5, i => TimeSpan.FromMilliseconds(50), ((result, i) => logger.LogWarning($"Failed to call Pricing_Service", result))); return Task.Run(() => { HttpResponseMessage responseMessage = retryPolicy.Execute(() => { var a = httpClient.SendAsync(request) .Result; return a; }); IdentityServiceResponse response = JsonSerializer.Deserialize<IdentityServiceResponse>(responseMessage.Content.ReadAsStringAsync() .Result); return response.AccessToken; }); } ``` I have setup the test below to stress the retry logic: ``` c# private WireMockServer identityServerMock; [OneTimeSetUp] public void Before() { WireMockServerSettings settings = new WireMockServerSettings(); settings.Urls = new[] {"http://+:9000"}; identityServerMock = WireMockServer.Start(settings); } [OneTimeTearDown] public void After() { identityServerMock.Dispose(); } [TearDown] public void AfterEach() { identityServerMock.Reset(); } [Test] public void GetToken_Should_Retry_500_Errors() { IdentityServiceResponse response = new IdentityServiceResponse { AccessToken = "testus", ExpiresIn = 3600, TokenType = "Bearer", Scope = "scope" }; const string scenario = "retry 500"; const string state1 = "pass"; const string state2 = "after pass"; identityServerMock.Given(Request.Create().WithPath("/connect/token").UsingPost()) .InScenario(scenario) .WillSetStateTo(state1) .RespondWith( Response.Create() .WithStatusCode(500)); identityServerMock.Given(Request.Create().WithPath("/connect/token").UsingPost()) .InScenario(scenario) .WhenStateIs(state1) .WillSetStateTo(state2) .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(JsonSerializer.Serialize(response))); Mock<ILogger> loggerMock = new Mock<ILogger>(); IIdentityService service = new IdentityService(loggerMock.Object, new HttpClient(), "localhost:9000"); string token = service.GetToken("testus", "pass", "client_credentials", "scope").Result; Assert.That(token, Is.EqualTo(response.AccessToken)); } ``` Unfortunately, I am getting this error upon making the second call to /connect/token: The request message was already sent. Cannot send the same request message multiple times. Can someone help point me in the right direction? I believe I am not switching scenario states correctly, but I am not sure what I am doing incorrectly. Thank you for your help, Jec
adam added the question label 2025-12-29 15:20:14 +01:00
adam closed this issue 2025-12-29 15:20:14 +01:00
Author
Owner

@StefH commented on GitHub (Oct 9, 2020):

Hello @jecjackal , this issue is not related to WireMock.Net

I suggest you take a look at:
https://stackoverflow.com/questions/54870415/receiving-error-the-request-message-was-already-sent-when-using-polly

@StefH commented on GitHub (Oct 9, 2020): Hello @jecjackal , this issue is not related to WireMock.Net I suggest you take a look at: https://stackoverflow.com/questions/54870415/receiving-error-the-request-message-was-already-sent-when-using-polly
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/WireMock.Net-wiremock#303