public void AddTask(object xcEvent, object publicMember, object internalMember,
                            object context, object sender, [CallerMemberName] string functionName = null)
        {
            RegisterSender(sender);

            var functionParameter = FunctionParameterFactory.CreateFunctionParameter(xcEvent,
                                                                                     publicMember,
                                                                                     internalMember,
                                                                                     context, ComponentName,
                                                                                     StateMachineName, functionName);

            string requestId = functionParameter.RequestId;

            _taskQueue.Enqueue(functionParameter);

            Action <FunctionResult> resultHandler = null;

            resultHandler = delegate(FunctionResult result)
            {
                if (result.RequestId == requestId)
                {
                    NewTaskFunctionResult -= resultHandler;

                    try
                    {
                        if (publicMember != null && result.PublicMember != null)
                        {
                            var newPublicMember = SerializationHelper.DeserializeObjectFromType(publicMember.GetType(), result.PublicMember);

                            XCClone.Clone(newPublicMember, publicMember);
                        }
                        if (internalMember != null && result.InternalMember != null)
                        {
                            var newInternalMember = SerializationHelper.DeserializeObjectFromType(internalMember.GetType(), result.InternalMember);
                            XCClone.Clone(newInternalMember, internalMember);
                        }
                    }
                    catch (Exception e)
                    {
                    }

                    lock (_senderWrapperBySender)
                    {
                        _senderWrapperBySender[sender].TriggerSender(result, context);
                    }
                }
            };

            NewTaskFunctionResult += resultHandler;
        }
        public async Task <FunctionResult> AddTaskAsync(object xcEvent, object publicMember, object internalMember,
                                                        object context, object sender, [CallerMemberName] string functionName = null)
        {
            if (xcEvent == null)
            {
                throw new ValidationException("Event should not be null");
            }
            if (publicMember == null)
            {
                throw new ValidationException("Public member should not be null");
            }
            if (internalMember == null)
            {
                throw new ValidationException("Internal member should not be null");
            }
            if (context == null)
            {
                throw new ValidationException("Context should not be null");
            }
            if (sender == null)
            {
                throw new ValidationException("Sender should not be null");
            }

            RegisterSender(sender);

            var functionParameter = FunctionParameterFactory.CreateFunctionParameter(xcEvent,
                                                                                     publicMember,
                                                                                     internalMember,
                                                                                     context, ComponentName,
                                                                                     StateMachineName, functionName);

            var requestId = functionParameter.RequestId;

            var taskCompletionSource = new TaskCompletionSource <FunctionResult>();

            Action <FunctionResult> resultHandler = null;

            resultHandler = delegate(FunctionResult result)
            {
                if (result.RequestId != requestId)
                {
                    return;
                }

                NewTaskFunctionResult -= resultHandler;

                lock (_pendingRequests)
                {
                    _pendingRequests.Remove(requestId);
                }

                taskCompletionSource.SetResult(result);
            };

            lock (_pendingRequests)
            {
                _pendingRequests.Add(requestId);
            }

            NewTaskFunctionResult += resultHandler;

            _taskQueue.Enqueue(functionParameter);

            var cancellationTokenSource = new CancellationTokenSource();
            var timeoutValue            = FunctionsFactory.Instance.Configuration.TimeoutInMillis;

            if (timeoutValue.HasValue)
            {
                cancellationTokenSource.CancelAfter(TimeSpan.FromMilliseconds(timeoutValue.Value));

                cancellationTokenSource.Token.Register(() => taskCompletionSource.TrySetCanceled());
            }

            try {
                return(await taskCompletionSource.Task);
            } catch (TaskCanceledException) {
                return(new FunctionResult
                {
                    IsError = true,
                    ErrorMessage = $"Timeout exceeded ({timeoutValue} ms)"
                });
            } catch (Exception e) {
                return(new FunctionResult
                {
                    IsError = true,
                    ErrorMessage = e.ToString()
                });
            }
        }