diff --git a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs index 5e7180a72..74aac829c 100644 --- a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs +++ b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs @@ -12,6 +12,7 @@ using WireMock.Server; using WireMock.Settings; using WireMock.Util; +using System.Threading.Tasks; namespace WireMock.Net.ConsoleApplication { @@ -521,9 +522,29 @@ public static void Run() .WithBodyAsJson(new { Id = "5bdf076c-5654-4b3e-842c-7caf1fabf8c9" })); server .Given(Request.Create().WithPath("/random200or505").UsingGet()) - .RespondWith(Response.Create().WithCallback(request => new ResponseMessage + .RespondWith(Response.Create().WithCallback(request => { - StatusCode = new Random().Next(1, 100) == 1 ? 504 : 200 + int code = new Random().Next(1, 2) == 1 ? 505 : 200; + return new ResponseMessage + { + BodyData = new BodyData { BodyAsString = "random200or505:" + code, DetectedBodyType = Types.BodyType.String }, + StatusCode = code + }; + })); + + server + .Given(Request.Create().WithPath("/random200or505async").UsingGet()) + .RespondWith(Response.Create().WithCallback(async request => + { + await Task.Delay(1); + + int code = new Random().Next(1, 2) == 1 ? 505 : 200; + + return new ResponseMessage + { + BodyData = new BodyData { BodyAsString = "random200or505async:" + code, DetectedBodyType = Types.BodyType.String }, + StatusCode = code + }; })); System.Console.WriteLine(JsonConvert.SerializeObject(server.MappingModels, Formatting.Indented)); diff --git a/src/WireMock.Net/ResponseBuilders/ICallbackResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/ICallbackResponseBuilder.cs index bd06ef902..27ddec154 100644 --- a/src/WireMock.Net/ResponseBuilders/ICallbackResponseBuilder.cs +++ b/src/WireMock.Net/ResponseBuilders/ICallbackResponseBuilder.cs @@ -1,19 +1,27 @@ -using System; -using JetBrains.Annotations; -using WireMock.ResponseProviders; - -namespace WireMock.ResponseBuilders -{ - /// - /// The CallbackResponseBuilder interface. - /// - public interface ICallbackResponseBuilder : IResponseProvider - { - /// - /// The callback builder - /// - /// The . - [PublicAPI] - IResponseBuilder WithCallback([NotNull] Func callbackHandler); - } +using System; +using System.Threading.Tasks; +using JetBrains.Annotations; +using WireMock.ResponseProviders; + +namespace WireMock.ResponseBuilders +{ + /// + /// The CallbackResponseBuilder interface. + /// + public interface ICallbackResponseBuilder : IResponseProvider + { + /// + /// The callback builder + /// + /// The . + [PublicAPI] + IResponseBuilder WithCallback([NotNull] Func callbackHandler); + + /// + /// The async callback builder + /// + /// The . + [PublicAPI] + IResponseBuilder WithCallback([NotNull] Func> callbackHandler); + } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/Response.WithCallback.cs b/src/WireMock.Net/ResponseBuilders/Response.WithCallback.cs new file mode 100644 index 000000000..34e68931b --- /dev/null +++ b/src/WireMock.Net/ResponseBuilders/Response.WithCallback.cs @@ -0,0 +1,60 @@ +using System; +using System.Threading.Tasks; +using WireMock.Validation; + +namespace WireMock.ResponseBuilders +{ + public partial class Response + { + /// + /// A delegate to execute to generate the response. + /// + public Func Callback { get; private set; } + + /// + /// A delegate to execute to generate the response async. + /// + public Func> CallbackAsync { get; private set; } + + /// + /// Defines if the method WithCallback(...) is used. + /// + public bool WithCallbackUsed { get; private set; } + + /// + public IResponseBuilder WithCallback(Func callbackHandler) + { + Check.NotNull(callbackHandler, nameof(callbackHandler)); + + return WithCallbackInternal(true, callbackHandler); + } + + /// + public IResponseBuilder WithCallback(Func> callbackHandler) + { + Check.NotNull(callbackHandler, nameof(callbackHandler)); + + return WithCallbackInternal(true, callbackHandler); + } + + private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func callbackHandler) + { + Check.NotNull(callbackHandler, nameof(callbackHandler)); + + WithCallbackUsed = withCallbackUsed; + Callback = callbackHandler; + + return this; + } + + private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func> callbackHandler) + { + Check.NotNull(callbackHandler, nameof(callbackHandler)); + + WithCallbackUsed = withCallbackUsed; + CallbackAsync = callbackHandler; + + return this; + } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/Response.cs b/src/WireMock.Net/ResponseBuilders/Response.cs index ee6715b98..061552b88 100644 --- a/src/WireMock.Net/ResponseBuilders/Response.cs +++ b/src/WireMock.Net/ResponseBuilders/Response.cs @@ -42,16 +42,6 @@ public partial class Response : IResponseBuilder /// public ResponseMessage ResponseMessage { get; } - /// - /// A delegate to execute to generate the response. - /// - public Func Callback { get; private set; } - - /// - /// Defines if the method WithCallback(...) is used. - /// - public bool WithCallbackUsed { get; private set; } - /// /// Creates this instance. /// @@ -311,25 +301,6 @@ public IResponseBuilder WithDelay(int milliseconds) return WithDelay(TimeSpan.FromMilliseconds(milliseconds)); } - /// - public IResponseBuilder WithCallback(Func callbackHandler) - { - Check.NotNull(callbackHandler, nameof(callbackHandler)); - - return WithCallbackInternal(true, callbackHandler); - } - - /// - private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func callbackHandler) - { - Check.NotNull(callbackHandler, nameof(callbackHandler)); - - WithCallbackUsed = withCallbackUsed; - Callback = callbackHandler; - - return this; - } - /// public async Task ProvideResponseAsync(RequestMessage requestMessage, IWireMockServerSettings settings) { @@ -365,13 +336,20 @@ string RemoveFirstOccurrence(string source, string find) } ResponseMessage responseMessage; - if (Callback == null) + if (Callback == null && CallbackAsync == null) { responseMessage = ResponseMessage; } else { - responseMessage = Callback(requestMessage); + if (Callback != null) + { + responseMessage = Callback(requestMessage); + } + else + { + responseMessage = await CallbackAsync(requestMessage); + } if (!WithCallbackUsed) { diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithCallbackTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithCallbackTests.cs index 510b5f1b1..1fbe3f791 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithCallbackTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithCallbackTests.cs @@ -13,6 +13,35 @@ public class ResponseWithCallbackTests { private readonly WireMockServerSettings _settings = new WireMockServerSettings(); + [Fact] + public async Task Response_WithCallbackAsync() + { + // Assign + var requestMessage = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1"); + var response = Response.Create() + .WithCallback(async request => + { + await Task.Delay(1); + + return new ResponseMessage + { + BodyData = new BodyData + { + DetectedBodyType = BodyType.String, + BodyAsString = request.Path + "Bar" + }, + StatusCode = 302 + }; + }); + + // Act + var responseMessage = await response.ProvideResponseAsync(requestMessage, _settings); + + // Assert + responseMessage.BodyData.BodyAsString.Should().Be("/fooBar"); + responseMessage.StatusCode.Should().Be(302); + } + [Fact] public async Task Response_WithCallback() {