public async Task PublishAsync(EventPublishData data, PublishPreferences preferences) { var eventDesc = new EventDescriptor { Service = data.Service, Event = data.Event }; var subscribers = _eventSubscriber.GetSubscribers(eventDesc).ToList(); if (subscribers.Count == 0) { return; } foreach (var subscriber in subscribers) { var invokeData = new MethodInvocationData { IntentId = _idGenerator.NewId(), Service = subscriber.Service, Method = subscriber.Method, Parameters = data.Parameters, FlowContext = data.FlowContext, Caller = new CallerDescriptor(data.Service, data.Event, data.IntentId) }; InvokeInBackground(invokeData, preferences); } }
/// <summary> /// 保存事件 /// 作者:郭明 /// 日期:2017年11月15日 /// </summary> /// <param name="events"></param> /// <param name="transaction"></param> /// <returns></returns> public async Task <List <EventLogEntry> > SaveEventAsync(List <EventLogEntry> LogEntrys, IDbTransaction transaction) { if (transaction == null) { throw new ArgumentNullException("transaction", $"A {typeof(DbTransaction).FullName} is required as a pre-requisite to save the event."); } var sqlParamtersList = new List <DynamicParameters>(); foreach (var eventLogEntry in LogEntrys) { if (eventLogEntry.EventId <= 0) { eventLogEntry.EventId = _uniqueIdGenerator.NewId(); } var sqlParamters = new DynamicParameters(); sqlParamters.Add("EventId", eventLogEntry.EventId, System.Data.DbType.Int64, System.Data.ParameterDirection.Input, 6); sqlParamters.Add("MessageId", eventLogEntry.MessageId, System.Data.DbType.StringFixedLength, System.Data.ParameterDirection.Input, 50); sqlParamters.Add("TraceId", eventLogEntry.TraceId, System.Data.DbType.StringFixedLength, System.Data.ParameterDirection.Input, 50); sqlParamters.Add("EventTypeName", eventLogEntry.EventTypeName, System.Data.DbType.StringFixedLength, System.Data.ParameterDirection.Input, 500); sqlParamters.Add("State", eventLogEntry.State, System.Data.DbType.Int32, System.Data.ParameterDirection.Input, 4); sqlParamters.Add("TimesSent", 0, System.Data.DbType.Int32, System.Data.ParameterDirection.Input, 4); sqlParamters.Add("CreationTime", DateTime.UtcNow, System.Data.DbType.Date, System.Data.ParameterDirection.Input, 4); sqlParamters.Add("Content", eventLogEntry.Content, System.Data.DbType.StringFixedLength, System.Data.ParameterDirection.Input); sqlParamtersList.Add(sqlParamters); } await transaction.Connection.ExecuteAsync($"insert into {_mySqlConfiguration.TablePrefix}EventLogs(EventId,MessageId,TraceId,EventTypeName,State,TimesSent,CreationTime,Content) values(@EventId,@MessageId,@TraceId,@EventTypeName,@State,@TimesSent,@CreationTime,@Content)", sqlParamtersList, transaction : transaction ); return(LogEntrys); }
public bool TryRegisterNew(object taskCompletionSource, out TriggerReference triggerReference) { if (taskCompletionSource == null) { throw new ArgumentNullException(nameof(taskCompletionSource)); } if (!TaskCompletionSourceAccessor.IsTaskCompletionSource(taskCompletionSource)) { throw new ArgumentException($"Input object must be a TaskCompletionSource`1, but got {taskCompletionSource.GetType()}", nameof(taskCompletionSource)); } var task = TaskCompletionSourceAccessor.GetTask(taskCompletionSource); triggerReference = task.AsyncState as TriggerReference; if (triggerReference != null) { return(false); } triggerReference = new TriggerReference { Id = _numericIdGenerator.NewId() }; task.SetAsyncState(triggerReference); return(true); }
public Task Execute <TParameters>(IProxy proxy, MethodInfo methodInfo, ref TParameters parameters) where TParameters : IValueContainer { var serviceProxyContext = (ServiceProxyContext)proxy.Context; var intent = new ExecuteRoutineIntent { Id = _numericIdGenerator.NewId(), ServiceId = serviceProxyContext.Descriptor.Id, MethodId = _routineMethodIdProvider.GetId(methodInfo), Parameters = parameters }; var taskResultType = // Dispose() does not return a task, and is the only exception. #warning check if it's really IDisposable.Dispose methodInfo.ReturnType == typeof(void) ? TaskAccessor.VoidTaskResultType : TaskAccessor.GetTaskResultType(methodInfo.ReturnType); var taskState = new RoutineReference { IntentId = intent.Id #warning must have id of actual routine for dynamic subscription (subscribe after a routine already scheduled). }; var proxyTask = TaskAccessor.CreateTask(taskState, taskResultType); bool executeInline = !_transitionScope.IsActive || !IsCalledByRoutine( _transitionScope.CurrentMonitor.Context, // Skip 2 stack frames: current method and dynamically-generated proxy. // WARNING! DO NOT PUT 'new StackFrame()' into a helper method! new StackFrame(skipFrames: 2, fNeedFileInfo: false)); if (executeInline) { ExecuteAndAwaitInBackground(intent, proxyTask); } else { _transitionScope.CurrentMonitor.RegisterIntent(intent, proxyTask); } return(proxyTask); }
internal void ScheduleRoutineFromEvent(EventSubscriberDescriptor eventSubscriberDescriptor, RoutineEventData raisedEventData) { var intentId = _idGenerator.NewId(); var pregeneratedRoutineId = intentId.ToString(); var routineDescriptor = new RoutineDescriptor { IntentId = intentId, MethodId = eventSubscriberDescriptor.MethodId, RoutineId = pregeneratedRoutineId }; var eventData = new RoutineEventData { ServiceId = eventSubscriberDescriptor.ServiceId, Routine = routineDescriptor, Caller = new CallerDescriptor { ServiceId = raisedEventData.ServiceId }, Parameters = raisedEventData.Parameters }; var eventEnvelope = new RoutineEventEnvelope { CloudEventsVersion = CloudEventsEnvelope.Version, EventType = DasyncCloudEventsTypes.InvokeRoutine.Name, EventTypeVersion = DasyncCloudEventsTypes.InvokeRoutine.Version, Source = "/" + (raisedEventData.ServiceId?.ServiceName ?? ""), EventID = intentId.ToString(), EventTime = DateTimeOffset.Now, ContentType = "application/json", Data = CloudEventsSerialization.Serialize(eventData) }; var fileName = intentId.ToString() + ".json"; var filePath = Path.Combine(_transitionsDirectory, fileName); var content = CloudEventsSerialization.Serialize(eventEnvelope); File.WriteAllText(filePath, content, Encoding.UTF8); }
public CancellationTokenSourceState Register(CancellationTokenSource source) { var state = (CancellationTokenSourceState)source.GetState(); if (state == null) { state = new CancellationTokenSourceState { Id = _idGenerator.NewId(), CancelTime = source.GetCancellationTime() }; source.SetState(state); TryAdd(state.Id, source); } else if (!TryGet(state.Id, out var otherSource)) { TryAdd(state.Id, source); } return(state); }
public async Task <long> Test() { return(await Task.FromResult(uniqueIdGenerator.NewId())); }
public async Task HandleAsync(PathString basePath, HttpContext context, CancellationToken ct) { var isQueryRequest = context.Request.Method == "GET"; var isCommandRequest = context.Request.Method == "POST"; if (!isQueryRequest && !isCommandRequest) { await ReplyWithTextError(context.Response, 405, "Only GET and POST verbs are allowed"); return; } var headers = context.Response.Headers; headers.Add(DasyncHttpHeaders.PoweredBy, "D-ASYNC"); var basePathSegmentCount = basePath.Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Length; var pathSegments = context.Request.Path.Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Skip(basePathSegmentCount).ToArray(); if (pathSegments.Length == 0) { await ReplyWithTextError(context.Response, 404, "Empty request URL"); return; } var serviceId = new ServiceId { Name = pathSegments[0] }; if (!_serviceResolver.TryResolve(serviceId, out var serviceReference)) { await ReplyWithTextError(context.Response, 404, $"Service '{serviceId.Name}' is not registered"); return; } if (serviceReference.Definition.Type == ServiceType.External) { await ReplyWithTextError(context.Response, 404, $"Cannot invoke external service '{serviceReference.Definition.Name}' on your behalf"); return; } if (pathSegments.Length == 1) { await ReplyWithTextError(context.Response, 404, "The request URL does not contain a service method"); return; } var methodId = new MethodId { Name = pathSegments[1] }; string methodIntentId = null; if (pathSegments.Length == 3) { methodIntentId = pathSegments[2]; if (isQueryRequest) { await HandleResultPoll(context, serviceReference.Id, methodId, methodIntentId); return; } } if (pathSegments.Length > 3) { await ReplyWithTextError(context.Response, 404, "The request URL contains extra segments"); return; } var contentType = context.Request.GetContentType(); ISerializer serializer; try { serializer = GetSerializer(contentType, isQueryRequest); } catch (ArgumentException) { await ReplyWithTextError(context.Response, 406, $"The Content-Type '{contentType.MediaType}' is not supported"); return; } if (!_methodResolver.TryResolve(serviceReference.Definition, methodId, out var methodReference)) { await ReplyWithTextError(context.Response, 404, $"The service '{serviceReference.Definition.Name}' does not have method '{methodId.Name}'"); return; } if (isQueryRequest && !methodReference.Definition.IsQuery) { await ReplyWithTextError(context.Response, 404, $"The method '{methodId.Name}' of service '{serviceReference.Definition.Name}' is a command, but not a query, thus must be invoked with the POST verb"); return; } MethodInvocationData invokeData = null; MethodContinuationData continueData = null; IValueContainer parametersContainer; bool compressResponse = false; bool respondWithEnvelope = false; if (isQueryRequest) { var inputObject = new JObject(); foreach (var kvPair in context.Request.Query) { if (kvPair.Value.Count == 0) { continue; } var parameterName = kvPair.Key; if (kvPair.Value.Count == 1) { var parameterValue = kvPair.Value[0]; inputObject.Add(parameterName, parameterValue); } else { var values = new JArray(); foreach (var value in kvPair.Value) { values.Add(value); } inputObject.Add(parameterName, values); } } var parametersJson = inputObject.ToString(); parametersContainer = new SerializedValueContainer(parametersJson, _jsonSerializer); invokeData = new MethodInvocationData { Service = serviceId, Method = methodId, Parameters = parametersContainer, Caller = GetCaller(context.Request.Headers) }; } else { var payloadStream = context.Request.Body; var encoding = context.Request.GetContentEncoding(); if (!string.IsNullOrEmpty(encoding)) { if ("gzip".Equals(encoding, StringComparison.OrdinalIgnoreCase)) { compressResponse = true; payloadStream = new GZipStream(payloadStream, CompressionMode.Decompress, leaveOpen: true); } else if ("deflate".Equals(encoding, StringComparison.OrdinalIgnoreCase)) { payloadStream = new DeflateStream(payloadStream, CompressionMode.Decompress, leaveOpen: true); } else { await ReplyWithTextError(context.Response, 406, $"The Content-Encoding '{encoding}' is not supported"); return; } } var envelopeType = context.Request.Headers.GetValue(DasyncHttpHeaders.Envelope); if (string.IsNullOrEmpty(envelopeType)) { var payload = await payloadStream.ToBytesAsync(); parametersContainer = new SerializedValueContainer(payload, serializer); if (string.IsNullOrEmpty(methodIntentId)) { invokeData = new MethodInvocationData { Service = serviceId, Method = methodId, Parameters = parametersContainer, Caller = GetCaller(context.Request.Headers) }; } else { continueData = new MethodContinuationData { Service = serviceId, Method = methodId.CopyTo(new PersistedMethodId()), Result = parametersContainer, Caller = GetCaller(context.Request.Headers) }; continueData.Method.IntentId = methodIntentId; // TODO: get ETag from the query string } } else if (envelopeType.Equals("invoke", StringComparison.OrdinalIgnoreCase)) { respondWithEnvelope = true; invokeData = await DeserializeAsync <MethodInvocationData>(serializer, payloadStream); } else if (envelopeType.Equals("continue", StringComparison.OrdinalIgnoreCase)) { respondWithEnvelope = true; continueData = await DeserializeAsync <MethodContinuationData>(serializer, payloadStream); } else { await ReplyWithTextError(context.Response, 406, $"Unknown envelope type '{envelopeType}'"); return; } } var intentId = context.Request.Headers.GetValue(DasyncHttpHeaders.IntentId) ?? _idGenerator.NewId(); var externalRequestId = context.Request.Headers.GetValue(DasyncHttpHeaders.RequestId); var externalCorrelationId = context.Request.Headers.GetValue(DasyncHttpHeaders.CorrelationId); var isRetry = context.Request.Headers.IsRetry(); var rfc7240Preferences = context.Request.Headers.GetRFC7240Preferences(); var isHttpRequestBlockingExecution = !(rfc7240Preferences.RespondAsync == true); var waitTime = rfc7240Preferences.Wait; if (waitTime > MaxLongPollTime) { waitTime = MaxLongPollTime; } var waitForResult = isHttpRequestBlockingExecution || waitTime > TimeSpan.Zero; var communicatorMessage = new HttpCommunicatorMessage { IsRetry = isRetry, RequestId = externalRequestId, WaitForResult = waitForResult }; if (invokeData != null) { if (invokeData.IntentId == null) { invokeData.IntentId = intentId; } var invokeTask = _localTransitionRunner.RunAsync(invokeData, communicatorMessage); if (isHttpRequestBlockingExecution) { var invocationResult = await invokeTask; if (invocationResult.Outcome == InvocationOutcome.Complete) { await RespondWithMethodResult(context.Response, invocationResult.Result, serializer, respondWithEnvelope, compressResponse); return; } if (waitForResult) { var taskResult = await TryWaitForResultAsync( serviceReference.Id, methodId, intentId, waitTime); if (taskResult != null) { await RespondWithMethodResult(context.Response, taskResult, serializer, respondWithEnvelope, compressResponse); return; } } } else { // TODO: continue 'invokeTask' and handle exceptions in background } communicatorMessage.WaitForResult = false; var location = string.Concat(context.Request.Path, "/", intentId); context.Response.Headers.Add("Location", location); context.Response.Headers.Add(DasyncHttpHeaders.IntentId, intentId); context.Response.StatusCode = DasyncHttpCodes.Scheduled; } else if (continueData != null) { if (continueData.IntentId == null) { continueData.IntentId = intentId; } var continueTask = _localTransitionRunner.ContinueAsync(continueData, communicatorMessage); // TODO: continue 'continueTask' in backgraound to handle exceptions context.Response.Headers.Add("Location", context.Request.Path.ToString()); context.Response.Headers.Add(DasyncHttpHeaders.IntentId, continueData.Method.IntentId); context.Response.StatusCode = DasyncHttpCodes.Scheduled; } }
private async void RunMessageInBackground(Message message) { if (message.DeliverAt.HasValue && message.DeliverAt > DateTime.UtcNow) { await Task.Delay(message.DeliverAt.Value - DateTime.UtcNow); } else { await Task.Yield(); } var ct = CancellationToken.None; if (message.IsEvent) { var serviceId = Serializer.Deserialize <ServiceId>(message[nameof(ServiceId)]); var eventId = Serializer.Deserialize <EventId>(message[nameof(EventId)]); var eventDesc = new EventDescriptor { EventId = eventId, ServiceId = serviceId }; var subscribers = DataStore.GetEventSubscribers(eventDesc); foreach (var subscriber in subscribers) { var routineId = Interlocked.Increment(ref DataStore.RoutineCounter); var routineRecord = new RoutineStateRecord { ETag = DateTime.UtcNow.Ticks.ToString("X16"), Id = routineId.ToString(), Completion = new TaskCompletionSource <string>() }; lock (DataStore.Routines) { DataStore.Routines.Add(routineRecord.Id, routineRecord); } var transitionDescriptor = new TransitionDescriptor { Type = TransitionType.InvokeRoutine, ETag = routineRecord.ETag }; var routineDescriptor = new RoutineDescriptor { MethodId = subscriber.MethodId, IntentId = _uniqueIdGenerator.NewId(), RoutineId = routineRecord.Id, ETag = routineRecord.ETag }; var invokeRoutineMessage = new Message { //["IntentId"] = _serializer.Serialize(intent.Id), [nameof(TransitionDescriptor)] = Serializer.SerializeToString(transitionDescriptor), [nameof(ServiceId)] = Serializer.SerializeToString(subscriber.ServiceId), [nameof(RoutineDescriptor)] = Serializer.SerializeToString(routineDescriptor), ["Parameters"] = message["Parameters"] }; DataStore.ScheduleMessage(invokeRoutineMessage); } } else { for (; ;) { using (_serviceProviderScope.New()) { var carrier = new TransitionCarrier(this, message); carrier.Initialize(); //var transitionInfo = await data.GetTransitionDescriptorAsync(ct); //if (transitionInfo.Type == TransitionType.InvokeRoutine || // transitionInfo.Type == TransitionType.ContinueRoutine) //{ // var routineDescriptor = await data.GetRoutineDescriptorAsync(ct); // if (!string.IsNullOrEmpty(transitionInfo.ETag) && // transitionInfo.ETag != routineDescriptor.ETag) // { // // Ignore - stale duplicate message // return; // } //} try { await _transitionRunner.RunAsync(carrier, ct); break; } catch (ConcurrentRoutineExecutionException) { // re-try continue; } } } } }
public async Task <long> Test() { return(uniqueIdGenerator.NewId()); }
public Task Execute <TParameters>(IProxy proxy, MethodInfo methodInfo, ref TParameters parameters) where TParameters : IValueContainer { var serviceProxyContext = (ServiceProxyContext)proxy.Context; var methodDefinition = serviceProxyContext.Definition.FindMethod(methodInfo); if (methodDefinition == null || methodDefinition.IsIgnored) { var invoker = _methodInvokerFactory.Create(methodInfo); return(invoker.Invoke(proxy, parameters)); } var intent = new ExecuteRoutineIntent { Id = _idGenerator.NewId(), Service = serviceProxyContext.Descriptor.Id, Method = _routineMethodIdProvider.GetId(methodInfo), Parameters = parameters }; Type taskResultType = methodInfo.ReturnType == typeof(void) ? TaskAccessor.VoidTaskResultType : TaskAccessor.GetTaskResultType(methodInfo.ReturnType); var taskState = new RoutineReference { ServiceId = intent.Service, MethodId = intent.Method, IntentId = intent.Id #warning must have id of actual routine for dynamic subscription (subscribe after a routine already scheduled). }; var proxyTask = TaskAccessor.CreateTask(taskState, taskResultType); bool invokedByRunningMethod = _transitionScope.IsActive && IsCalledByRoutine( _transitionScope.CurrentMonitor.Context, // Skip 2 stack frames: current method and dynamically-generated proxy. // WARNING! DO NOT PUT 'new StackFrame()' into a helper method! new StackFrame(skipFrames: 2, fNeedFileInfo: false)); bool ignoreTransaction = !invokedByRunningMethod; if (!ignoreTransaction && _transitionScope.IsActive) { var runningMethodSettings = _communicationSettingsProvider.GetMethodSettings( _transitionScope.CurrentMonitor.Context.MethodRef.Definition); if (!runningMethodSettings.Transactional) { ignoreTransaction = true; } } if (!ignoreTransaction) { var methodSettings = _communicationSettingsProvider.GetMethodSettings(methodDefinition); if (methodSettings.IgnoreTransaction) { ignoreTransaction = true; } } if (ignoreTransaction) { ExecuteAndAwaitInBackground(intent, proxyTask); } else { _transitionScope.CurrentMonitor.RegisterIntent(intent, proxyTask); } return(proxyTask); }
public async Task HandleAsync(PathString basePath, HttpContext context, CancellationToken ct) { var headers = context.Response.Headers; headers.Add(DasyncHttpHeaders.PoweredBy, "D-ASYNC"); var basePathSegmentCount = basePath.Value.Split('/', StringSplitOptions.RemoveEmptyEntries).Length; var pathSegments = context.Request.Path.Value.Split('/', StringSplitOptions.RemoveEmptyEntries).Skip(basePathSegmentCount).ToArray(); if (pathSegments.Length == 0 && context.Request.Query.ContainsKey("react")) { await HandleEventReactionAsync(null, context, ct); return; } if (pathSegments.Length == 0) { context.Response.StatusCode = 404; context.Response.ContentType = "text/plain"; await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("Empty request URL")); return; } var serviceName = pathSegments[0]; var serviceDefinition = _communicationModelProvider.Model.FindServiceByName(serviceName); if (serviceDefinition == null) { context.Response.StatusCode = 404; context.Response.ContentType = "text/plain"; await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes($"Service '{serviceName}' is not registered")); return; } if (serviceDefinition.Type == ServiceType.External) { context.Response.StatusCode = 403; // Forbidden context.Response.ContentType = "text/plain"; await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes($"Cannot invoke external service '{serviceName}' on your behalf")); return; } if (_eventDispatcher != null && pathSegments.Length == 1 && context.Request.Query.ContainsKey("react")) { await HandleEventReactionAsync(serviceDefinition, context, ct); return; } if (pathSegments.Length == 1) { context.Response.StatusCode = 404; context.Response.ContentType = "text/plain"; await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("The request URL does not contain a service method")); return; } if (_eventDispatcher != null && context.Request.Query.ContainsKey("subscribe")) { await HandleEventSubsciptionAsync(serviceDefinition, pathSegments[1], context, ct); return; } var methodName = pathSegments[1]; if (pathSegments.Length == 3) { await HandleResultPoll(context, serviceName, methodName, intentId : pathSegments[2]); return; } if (pathSegments.Length > 3) { context.Response.StatusCode = 404; context.Response.ContentType = "text/plain"; await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("The request URL contains extra segments")); return; } var isQueryRequest = context.Request.Method == "GET"; var isCommandRequest = context.Request.Method == "PUT" || context.Request.Method == "POST"; var contentType = context.Request.GetContentType(); var isJsonRequest = string.Equals(contentType.MediaType, "application/json", StringComparison.OrdinalIgnoreCase); var isDasyncJsonRequest = string.Equals(contentType.MediaType, "application/dasync+json", StringComparison.OrdinalIgnoreCase); if (!isQueryRequest && !isJsonRequest && !isDasyncJsonRequest) { context.Response.StatusCode = 406; // Not Acceptable context.Response.ContentType = "text/plain"; await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("The request content type is either not specified or not supported")); return; } if (!isQueryRequest && !isCommandRequest) { context.Response.StatusCode = 405; // Method Not Allowed context.Response.ContentType = "text/plain"; await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("The service method invocation must use one of these HTTP verbs: GET, POST, PUT")); return; } var routineMethodId = new RoutineMethodId { MethodName = methodName }; #warning Use model for method resolution instead MethodInfo routineMethod; try { routineMethod = _routineMethodResolver.Resolve(serviceDefinition, routineMethodId); } catch { context.Response.StatusCode = 404; context.Response.ContentType = "text/plain"; await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes($"The service '{serviceDefinition.Name}' does not have method '{methodName}'")); return; } #warning Use model to determine if the method is command or query var isQueryMethod = GetWordAndSynonyms.Contains(GetFirstWord(methodName)); if (isQueryRequest && !isQueryMethod) { context.Response.StatusCode = 404; context.Response.ContentType = "text/plain"; await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes($"The method '{methodName}' of service '{serviceDefinition.Name}' is a command, but not a query, thus must be invoked with POST or PUT verb")); return; } string parametersJson = null; ContinuationDescriptor continuationDescriptor = null; if (isQueryRequest) { var inputObject = new JObject(); foreach (var kvPair in context.Request.Query) { if (kvPair.Value.Count == 0) { continue; } var parameterName = kvPair.Key; if (kvPair.Value.Count == 1) { var parameterValue = kvPair.Value[0]; inputObject.Add(parameterName, parameterValue); } else { var values = new JArray(); foreach (var value in kvPair.Value) { values.Add(value); } inputObject.Add(parameterName, values); } } parametersJson = inputObject.ToString(); } else if (isJsonRequest) { parametersJson = await context.Request.ReadBodyAsStringAsync(contentType); } else { var inputJson = await context.Request.ReadBodyAsStringAsync(contentType); var envelope = JsonConvert.DeserializeObject <CommandEnvelope>(inputJson, JsonSettings); parametersJson = envelope.Parameters; continuationDescriptor = envelope.Continuation; } var methodInvoker = _methodInvokerFactory.Create(routineMethod); var parameterContainer = methodInvoker.CreateParametersContainer(); if (!string.IsNullOrWhiteSpace(parametersJson)) { if (isDasyncJsonRequest) { _dasyncJsonSerializer.Populate(parametersJson, parameterContainer); } else { JsonConvert.PopulateObject(parametersJson, parameterContainer, JsonSettings); } } var externalRequestId = context.Request.Headers.TryGetValue(DasyncHttpHeaders.RequestId, out var requestIdValues) && requestIdValues.Count > 0 ? requestIdValues[0] : null; var externalCorrelationId = context.Request.Headers.TryGetValue(DasyncHttpHeaders.CorrelationId, out var correlationIdValues) && correlationIdValues.Count > 0 ? correlationIdValues[0] : null; var rfc7240Preferences = GetPreferences(context.Request.Headers); var isHttpRequestBlockingExecution = !(rfc7240Preferences.RespondAsync == true); _transitionUserContext.Current = GetUserContext(context); _intentPreprocessor.PrepareContext(context); if (await _intentPreprocessor.PreprocessAsync(context, serviceDefinition, routineMethodId, parameterContainer).ConfigureAwait(false)) { return; } var serviceId = new ServiceId { ServiceName = serviceDefinition.Name }; var intentId = _idGenerator.NewId(); if (isQueryMethod) { var serviceInstance = _domainServiceProvider.GetService(serviceDefinition.Implementation); foreach (var postAction in _transitionActions) { await postAction.OnRoutineStartAsync(serviceDefinition, serviceId, routineMethodId, intentId); } Task task; try { task = methodInvoker.Invoke(serviceInstance, parameterContainer); if (routineMethod.ReturnType != typeof(void)) { try { await task; } catch { } } } catch (Exception ex) { if (ex is TargetInvocationException) { ex = ex.InnerException; } task = Task.FromException(ex); } var taskResult = task?.ToTaskResult() ?? new TaskResult(); foreach (var postAction in _transitionActions) { await postAction.OnRoutineCompleteAsync(serviceDefinition, serviceId, routineMethodId, intentId, taskResult); } await RespondWithRoutineResult(context, taskResult, isDasyncJsonRequest); } else { var intent = new ExecuteRoutineIntent { Id = intentId, ServiceId = new ServiceId { ServiceName = serviceDefinition.Name }, MethodId = routineMethodId, Parameters = parameterContainer, Continuation = continuationDescriptor }; var actions = new ScheduledActions { ExecuteRoutineIntents = new List <ExecuteRoutineIntent> { intent } }; var options = new TransitionCommitOptions { NotifyOnRoutineCompletion = isHttpRequestBlockingExecution, RequestId = externalRequestId, CorrelationId = externalCorrelationId ?? externalRequestId }; await _transitionCommitter.CommitAsync(actions, null, options, default); var waitTime = rfc7240Preferences.Wait; if (isHttpRequestBlockingExecution || waitTime > MaxLongPollTime) { waitTime = MaxLongPollTime; } if (waitTime > TimeSpan.Zero) { var cts = new CancellationTokenSource(); var completionSink = new TaskCompletionSource <TaskResult>(); _routineCompletionNotifier.NotifyCompletion(intent.ServiceId, intent.MethodId, intent.Id, completionSink, cts.Token); try { var taskResult = await completionSink.Task.WithTimeout(waitTime); await RespondWithRoutineResult(context, taskResult, isDasyncJsonRequest); return; } catch (TaskCanceledException) { cts.Cancel(); } } var location = context.Request.Path.ToString() + "/" + intent.Id; context.Response.Headers.Add("Location", location); context.Response.StatusCode = DasyncHttpCodes.Scheduled; return; } }