protected Task <Tuple <object, object[]> > InvokeAsync(IComparable instanceId, MethodInfo replicationMethod, object[] inputParameters) { Requires.Argument("instanceId", instanceId).NotNull(); Requires.Argument("replicationMethod", replicationMethod).NotNull(); StatefulProgramInstance instance = this.instanceManager.GetInstance(instanceId); if (instance == null) { throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "No instance was found with InstanceId: '{0}'", instanceId), "instanceId"); } return(instance.InvokeAsync(replicationMethod, inputParameters)); }
private void InvokeProcessRequestAsync <TRequestType, TResult>(TaskCompletionSource <TResult> taskProducer, StatefulServiceExecutionContext executionContext, string methodName, Tuple <Type, Type[], object[]> methodParams) { Exception exception = null; try { if (!typeof(IProcessHttpRequest).IsAssignableFrom(typeof(TRequestType)) && !typeof(IProcessTcpRequest).IsAssignableFrom(typeof(TRequestType))) { taskProducer.SetException(new NotSupportedException("Method not supported by the server")); return; } // Get Session Information StatefulProgramInstance instance = null; DateTime expiryTime; IComparable sessionId; object sessionObj = null; HttpListenerContext httpListenerContext = methodParams.Item3[methodParams.Item3.Length - 1] as HttpListenerContext; if (httpListenerContext != null) { sessionObj = httpListenerContext.Request; } else { // For TCP we smuggle the headers in IDictionary<string, string> passed via asyncState StreamWrapper streamWrapper = methodParams.Item3[methodParams.Item3.Length - 1] as StreamWrapper; sessionObj = streamWrapper != null ? streamWrapper.UserData : null; } if (!StatefulServiceReplica <TInstance> .GetSessionInformation(sessionObj, out sessionId, out expiryTime)) { // TODO: We do not support session expiry currently sessionId = Helpers.GenerateUniqueId(); expiryTime = DateTime.UtcNow.AddYears(100); } else { instance = this.instanceManager.GetInstance(sessionId); } // Create a new instance if necessary bool setSessionInformation = false; bool isExpired = sessionId != null && DateTime.UtcNow > expiryTime; if (instance == null) { this.CreateInstance(sessionId, null); instance = this.instanceManager.GetInstance(sessionId); setSessionInformation = true; } Action <Task> processRequestContinuation = delegate(Task task) { this.Invoke <StatefulServiceExecutionContext>( (cec) => { Exception exception1 = null; try { if (setSessionInformation) { if (httpListenerContext != null) { sessionObj = httpListenerContext.Response; } else { // For TCP we smuggle the headers in asyncObject sessionObj = (IDictionary <string, string>)methodParams.Item3[methodParams.Item3.Length - 1]; } StatefulServiceReplica <TInstance> .SetSessionInformation(sessionObj, sessionId, expiryTime); } if (!task.IsFaulted) { // Get the result from either the http task or task returned by Replicable method invocation. object result = null; if (typeof(IProcessTcpRequest).IsAssignableFrom(typeof(TRequestType))) { Task <Stream> tcpResponseTask = task as Task <Stream>; if (tcpResponseTask != null) { result = tcpResponseTask.Result; } else { Task <object> taskWithObj = task as Task <object>; result = (Stream)taskWithObj.Result; } } taskProducer.SetResult((TResult)result); } else { exception1 = task.Exception.InnerException ?? task.Exception; } if (isExpired) { this.DeleteInstance(sessionId); } } catch (Exception e) { AppTrace.TraceException(e, "StatefulServiceReplicaT.InvokeProcessRequestAsync"); exception1 = e; } finally { if (exception1 != null) { taskProducer.SetException(exception1); } } }); }; if (instance != null && !isExpired) { IEnumerable <ReplicableMethodInfo> matchingMethods = null; instance.TypeInfo.TryGetMatchingMethod("ProcessRequestAsync", methodParams.Item1, methodParams.Item2, out matchingMethods); int matchingMethodCount = matchingMethods != null?matchingMethods.Count() : 0; if (matchingMethodCount == 1 && matchingMethods.First().Type == ReplicableMethodInfo.MethodType.AsyncTask) { ReplicableMethodInfo methodInfo = matchingMethods.First(); Task <Tuple <object, object[]> > asyncInvocationTask = instance.InvokeAsync(methodInfo.Methods[0], methodParams.Item3); asyncInvocationTask.Wait(); Task task = (Task)asyncInvocationTask.Result.Item1; task.ContinueWith(processRequestContinuation); } else if (matchingMethodCount > 1) { exception = new AmbiguousMatchException(String.Format(CultureInfo.InvariantCulture, "Multiple methods with name '{0}' matching similar parameters were found", "ProcessRequestAsync")); } else if (typeof(IProcessHttpRequest).IsAssignableFrom(typeof(TRequestType))) { ((IProcessHttpRequest)instance.Instance).ProcessRequestAsync((HttpListenerContext)methodParams.Item3[0]) .ContinueWith(task => { processRequestContinuation(task); }, TaskContinuationOptions.ExecuteSynchronously); } else { ((IProcessTcpRequest)instance.Instance).ProcessRequestAsync((Stream)methodParams.Item3[0]) .ContinueWith(task => { processRequestContinuation(task); }, TaskContinuationOptions.ExecuteSynchronously); } } else { AppTrace.TraceMsg(TraceLogEventType.Warning, "StatefulServiceReplicaT.InvokeProcessRequestAsync", "Instance cannot be created for expired session cookie with session id '{0}'.", sessionId); taskProducer.SetException(new InvalidOperationException("Instance expired. Service cannot process request")); } } catch (Exception e) { AppTrace.TraceException(e, "StatefulServiceReplicaT.InvokeProcessRequestAsync"); exception = e; } finally { if (exception != null) { taskProducer.SetException(exception); } } }