diff --git a/Examples/03-FlowRequestResponse/ParallelFlowController.cs b/Examples/03-FlowRequestResponse/ParallelFlowController.cs index 04d79f5..9a8dc7a 100644 --- a/Examples/03-FlowRequestResponse/ParallelFlowController.cs +++ b/Examples/03-FlowRequestResponse/ParallelFlowController.cs @@ -56,7 +56,7 @@ namespace _03_FlowRequestResponse [Continuation] - public async Task HandleSecondQuoteResponse(QuoteResponseMessage message, IFlowParallelRequest parallelRequest) + public async ValueTask HandleSecondQuoteResponse(QuoteResponseMessage message, IFlowParallelRequest parallelRequest) { Console.WriteLine("[ParallelFlowController] Second quote response received"); SecondQuote = message.Quote; diff --git a/Tapeti.Flow/Default/FlowBindingMiddleware.cs b/Tapeti.Flow/Default/FlowBindingMiddleware.cs index 83564c8..877f890 100644 --- a/Tapeti.Flow/Default/FlowBindingMiddleware.cs +++ b/Tapeti.Flow/Default/FlowBindingMiddleware.cs @@ -50,6 +50,14 @@ namespace Tapeti.Flow.Default await HandleParallelResponse(messageContext); }); } + if (context.Result.Info.ParameterType == typeof(ValueTask)) + { + context.Result.SetHandler(async (messageContext, value) => + { + await (ValueTask)value; + await HandleParallelResponse(messageContext); + }); + } else if (context.Result.Info.ParameterType == typeof(void)) { context.Result.SetHandler((messageContext, value) => HandleParallelResponse(messageContext)); diff --git a/Tapeti.Flow/Default/FlowProvider.cs b/Tapeti.Flow/Default/FlowProvider.cs index 394377b..509ab64 100644 --- a/Tapeti.Flow/Default/FlowProvider.cs +++ b/Tapeti.Flow/Default/FlowProvider.cs @@ -38,6 +38,13 @@ namespace Tapeti.Flow.Default return new DelegateYieldPoint(context => SendRequest(context, message, responseHandlerInfo)); } + /// + public IYieldPoint YieldWithRequest(TRequest message, Func> responseHandler) + { + var responseHandlerInfo = GetResponseHandlerInfo(config, message, responseHandler); + return new DelegateYieldPoint(context => SendRequest(context, message, responseHandlerInfo)); + } + /// public IYieldPoint YieldWithRequestSync(TRequest message, Func responseHandler) { @@ -312,18 +319,31 @@ namespace Tapeti.Flow.Default return InternalAddRequest(message, responseHandler); } + public IFlowParallelRequestBuilder AddRequest(TRequest message, Func responseHandler) + { + return InternalAddRequest(message, responseHandler); + } public IFlowParallelRequestBuilder AddRequest(TRequest message, Func responseHandler) { return InternalAddRequest(message, responseHandler); } + public IFlowParallelRequestBuilder AddRequest(TRequest message, Func responseHandler) + { + return InternalAddRequest(message, responseHandler); + } public IFlowParallelRequestBuilder AddRequestSync(TRequest message, Action responseHandler) { return InternalAddRequest(message, responseHandler); } + public IFlowParallelRequestBuilder AddRequestSync(TRequest message, Action responseHandler) + { + return InternalAddRequest(message, responseHandler); + } + private IFlowParallelRequestBuilder InternalAddRequest(object message, Delegate responseHandler) { @@ -342,6 +362,11 @@ namespace Tapeti.Flow.Default return BuildYieldPoint(continuation, false, noRequestsBehaviour); } + public IYieldPoint Yield(Func> continuation, FlowNoRequestsBehaviour noRequestsBehaviour = FlowNoRequestsBehaviour.Exception) + { + throw new NotImplementedException(); + } + public IYieldPoint YieldSync(Func continuation, FlowNoRequestsBehaviour noRequestsBehaviour = FlowNoRequestsBehaviour.Exception) { diff --git a/Tapeti.Flow/IFlowProvider.cs b/Tapeti.Flow/IFlowProvider.cs index d8b7abe..3ac98de 100644 --- a/Tapeti.Flow/IFlowProvider.cs +++ b/Tapeti.Flow/IFlowProvider.cs @@ -23,6 +23,18 @@ namespace Tapeti.Flow IYieldPoint YieldWithRequest(TRequest message, Func> responseHandler); + /// + /// Publish a request message and continue the flow when the response arrives. + /// The request message must be marked with the [Request] attribute, and the + /// Response type must match. Used for asynchronous response handlers. + /// + /// + /// + /// + /// + IYieldPoint YieldWithRequest(TRequest message, Func> responseHandler); + + /// /// Publish a request message and continue the flow when the response arrives. /// The request message must be marked with the [Request] attribute, and the @@ -164,6 +176,16 @@ namespace Tapeti.Flow /// IFlowParallelRequestBuilder AddRequest(TRequest message, Func responseHandler); + /// + /// Publish a request message and continue the flow when the response arrives. + /// Note that the response handler can not influence the flow as it does not return a YieldPoint. + /// It can instead store state in the controller for the continuation passed to the Yield method. + /// Used for asynchronous response handlers. + /// + /// + /// + IFlowParallelRequestBuilder AddRequest(TRequest message, Func responseHandler); + /// /// This overload allows the response handler access to the IFlowParallelRequest interface, which /// can be used to add additional requests to the parallel request before the continuation method passed to the Yield method is called. @@ -171,6 +193,13 @@ namespace Tapeti.Flow /// IFlowParallelRequestBuilder AddRequest(TRequest message, Func responseHandler); + /// + /// This overload allows the response handler access to the IFlowParallelRequest interface, which + /// can be used to add additional requests to the parallel request before the continuation method passed to the Yield method is called. + /// + /// + IFlowParallelRequestBuilder AddRequest(TRequest message, Func responseHandler); + /// /// Publish a request message and continue the flow when the response arrives. /// Note that the response handler can not influence the flow as it does not return a YieldPoint. @@ -181,6 +210,13 @@ namespace Tapeti.Flow /// IFlowParallelRequestBuilder AddRequestSync(TRequest message, Action responseHandler); + /// + /// This overload allows the response handler access to the IFlowParallelRequest interface, which + /// can be used to add additional requests to the parallel request before the continuation method passed to the Yield method is called. + /// + /// + IFlowParallelRequestBuilder AddRequestSync(TRequest message, Action responseHandler); + /// There is no Sync overload with an IFlowParallelRequest parameter, as the AddRequest methods for that are /// async, so you should always await them. /// @@ -194,6 +230,19 @@ namespace Tapeti.Flow /// How the Yield method should behave when no requests have been added to the parallel request builder. IYieldPoint Yield(Func> continuation, FlowNoRequestsBehaviour noRequestsBehaviour = FlowNoRequestsBehaviour.Exception); + /// There is no Sync overload with an IFlowParallelRequest parameter, as the AddRequest methods for that are + /// async, so you should always await them. + /// + /// Constructs an IYieldPoint to continue the flow when responses arrive. + /// The continuation method is called when all responses have arrived. + /// Response handlers and the continuation method are guaranteed thread-safe access to the + /// controller and can store state. + /// Used for asynchronous continuation methods. + /// + /// The converge continuation method to be called when all responses have been handled. + /// How the Yield method should behave when no requests have been added to the parallel request builder. + IYieldPoint Yield(Func> continuation, FlowNoRequestsBehaviour noRequestsBehaviour = FlowNoRequestsBehaviour.Exception); + /// /// Constructs an IYieldPoint to continue the flow when responses arrive. /// The continuation method is called when all responses have arrived. diff --git a/appveyor.yml b/appveyor.yml index 14eabb1..80d0eb8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,7 +10,7 @@ before_build: - ps: build\UpdateVersion.ps1 environment: - pack_params: -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg -p:PublishRepositoryUrl=true -p:EmbedUntrackedSources=true --output output -p:Configuration=Release -p:p:ContinuousIntegrationBuild=true + pack_params: -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg -p:PublishRepositoryUrl=true -p:EmbedUntrackedSources=true --output output -p:Configuration=Release -p:p:ContinuousIntegrationBuild=true --verbosity detailed after_build: # Create NuGet packages