예제 #1
0
        public async Task ReleaseAsync_InvokesSingletonManager_WithExpectedValues()
        {
            CancellationToken  cancellationToken = new CancellationToken();
            SingletonAttribute attribute         = new SingletonAttribute();

            SingletonManager.SingletonLockHandle handle = new SingletonManager.SingletonLockHandle();

            Mock <SingletonManager> mockSingletonManager = new Mock <SingletonManager>(MockBehavior.Strict);

            mockSingletonManager.Setup(p => p.LockAsync(TestLockId, TestInstanceId, attribute, cancellationToken)).ReturnsAsync(handle);
            mockSingletonManager.Setup(p => p.ReleaseLockAsync(handle, cancellationToken)).Returns(Task.FromResult(true));

            SingletonLock singletonLock = new SingletonLock(TestLockId, TestInstanceId, attribute, mockSingletonManager.Object);

            Assert.False(singletonLock.IsHeld);
            await singletonLock.AcquireAsync(cancellationToken);

            Assert.True(singletonLock.IsHeld);
            await singletonLock.ReleaseAsync(cancellationToken);

            Assert.False(singletonLock.IsHeld);

            Assert.NotNull(singletonLock.AcquireStartTime);
            Assert.NotNull(singletonLock.AcquireEndTime);
            Assert.NotNull(singletonLock.ReleaseTime);
        }
예제 #2
0
        public async Task GetValueAsync_ReturnsExpectedValue()
        {
            SingletonLock value = (SingletonLock)(await _valueProvider.GetValueAsync());

            Assert.Equal(_lockId, value.Id);
            Assert.Equal(TestInstanceId, value.FunctionId);
        }
        public void GetValue_ReturnsExpectedValue()
        {
            SingletonLock value = (SingletonLock)_valueProvider.GetValue();

            Assert.Equal(_lockId, value.Id);
            Assert.Equal(TestInstanceId, value.FunctionId);
        }
예제 #4
0
 public static SingletonLock GetInstance()
 {
     lock (myLock)
     {
         if (myInstance == null)
         {
             myInstance = new SingletonLock();
         }
         return(myInstance);
     }
 }
        public void Constructor_SetsExpectedValues()
        {
            SingletonAttribute attribute = new SingletonAttribute();
            Mock<SingletonManager> mockSingletonManager = new Mock<SingletonManager>(MockBehavior.Strict);
            SingletonLock singletonLock = new SingletonLock(TestLockId, TestInstanceId, attribute, mockSingletonManager.Object);

            Assert.Equal(TestLockId, singletonLock.Id);
            Assert.Equal(TestInstanceId, singletonLock.FunctionId);
            Assert.Null(singletonLock.AcquireStartTime);
            Assert.Null(singletonLock.AcquireEndTime);
            Assert.Null(singletonLock.ReleaseTime);
        }
예제 #6
0
        private static async Task <SingletonLock> GetSingletonLockAsync(IReadOnlyDictionary <string, IValueProvider> parameters)
        {
            IValueProvider singletonValueProvider = null;
            SingletonLock  singleton = null;

            if (parameters.TryGetValue(SingletonValueProvider.SingletonParameterName, out singletonValueProvider))
            {
                singleton = (SingletonLock)(await singletonValueProvider.GetValueAsync());
            }

            return(singleton);
        }
예제 #7
0
        public void Constructor_SetsExpectedValues()
        {
            SingletonAttribute      attribute            = new SingletonAttribute();
            Mock <SingletonManager> mockSingletonManager = new Mock <SingletonManager>(MockBehavior.Strict);
            SingletonLock           singletonLock        = new SingletonLock(TestLockId, TestInstanceId, attribute, mockSingletonManager.Object);

            Assert.Equal(TestLockId, singletonLock.Id);
            Assert.Equal(TestInstanceId, singletonLock.FunctionId);
            Assert.Null(singletonLock.AcquireStartTime);
            Assert.Null(singletonLock.AcquireEndTime);
            Assert.Null(singletonLock.ReleaseTime);
        }
예제 #8
0
        public void ToInvokeString_ReturnsExpectedValue()
        {
            SingletonAttribute attribute = new SingletonAttribute();
            SingletonValueProvider localValueProvider = new SingletonValueProvider(_method, attribute.Scope, TestInstanceId, attribute, new SingletonManager());
            SingletonLock singletonLock = (SingletonLock)localValueProvider.GetValue();
            Assert.Equal("Scope: default", localValueProvider.ToInvokeString());

            attribute = new SingletonAttribute(@"{Region}\{Zone}");
            localValueProvider = new SingletonValueProvider(_method, @"Central\3", TestInstanceId, attribute, new SingletonManager());
            singletonLock = (SingletonLock)localValueProvider.GetValue();
            Assert.Equal(@"Scope: Central\3", localValueProvider.ToInvokeString());
        }
        public async Task GetOwnerAsync_InvokesSingletonManager_WithExpectedValues()
        {
            CancellationToken cancellationToken = new CancellationToken();
            SingletonAttribute attribute = new SingletonAttribute();

            Mock<SingletonManager> mockSingletonManager = new Mock<SingletonManager>(MockBehavior.Strict);
            string lockOwner = "ownerid";
            mockSingletonManager.Setup(p => p.GetLockOwnerAsync(TestLockId, cancellationToken)).ReturnsAsync(lockOwner);

            SingletonLock singletonLock = new SingletonLock(TestLockId, TestInstanceId, attribute, mockSingletonManager.Object);

            await singletonLock.GetOwnerAsync(cancellationToken);
        }
        public static void Run()
        {
            char key;

            while (true)
            {
                printMenu();

                key = Console.ReadKey().KeyChar;

                Console.WriteLine();
                switch (key)
                {
                case 'f':
                    FactoryMethodPatternExample.Display();
                    break;

                case 'a':
                    AbstractFactoryPatternExample.Display();
                    break;

                case 's':
                    SingletonPatternExample.Display();
                    SingletonLock.Display();
                    SingletonThreads.Display();
                    break;

                case 'l':
                    SingletonStaticFields.Display();
                    SingletonNestedClass.Display();
                    SingletonNestedLazy.Display();
                    break;

                case 'z':
                    SingletonLazy.Display();
                    break;

                case 'p':
                    PrototypePatternExample.Display();
                    PrototypePatternExampleComplex.Display();
                    break;

                case 'b':
                    BuilderPatternExample.Display();
                    break;

                case 'x': return;
                }
                Console.ReadKey();
            }
        }
        public async Task ToInvokeString_ReturnsExpectedValue()
        {
            SingletonManager       singletonManager   = new SingletonManager(null, null, null, null, null, new FixedHostIdProvider(TestHostId));
            SingletonAttribute     attribute          = new SingletonAttribute();
            SingletonValueProvider localValueProvider = new SingletonValueProvider(_method, attribute.ScopeId, TestInstanceId, attribute, singletonManager);
            SingletonLock          singletonLock      = (SingletonLock)(await localValueProvider.GetValueAsync());

            Assert.Equal("ScopeId: (null)", localValueProvider.ToInvokeString());

            attribute          = new SingletonAttribute(@"{Region}\{Zone}");
            localValueProvider = new SingletonValueProvider(_method, @"Central\3", TestInstanceId, attribute, singletonManager);
            singletonLock      = (SingletonLock)(await localValueProvider.GetValueAsync());
            Assert.Equal(@"ScopeId: Central\3", localValueProvider.ToInvokeString());
        }
 public static SingletonLock GetSingleton()
 {
     if (s_singleton == null)
     {
         lock (s_sync)
         {
             if (s_singleton == null)
             {
                 s_singleton = new SingletonLock();
             }
         }
     }
     return(s_singleton);
 }
예제 #13
0
        public async Task GetOwnerAsync_InvokesSingletonManager_WithExpectedValues()
        {
            CancellationToken  cancellationToken = new CancellationToken();
            SingletonAttribute attribute         = new SingletonAttribute();

            Mock <SingletonManager> mockSingletonManager = new Mock <SingletonManager>(MockBehavior.Strict);
            string lockOwner = "ownerid";

            mockSingletonManager.Setup(p => p.GetLockOwnerAsync(attribute, TestLockId, cancellationToken)).ReturnsAsync(lockOwner);

            SingletonLock singletonLock = new SingletonLock(TestLockId, TestInstanceId, attribute, mockSingletonManager.Object);

            await singletonLock.GetOwnerAsync(cancellationToken);
        }
        public async Task SingletonWatcher_GetStatus_ReturnsExpectedValue()
        {
            Mock <SingletonManager> mockSingletonManager = new Mock <SingletonManager>(MockBehavior.Strict, null, null, null, null, null, new FixedHostIdProvider(TestHostId), null);

            mockSingletonManager.Setup(p => p.GetLockOwnerAsync(_attribute, _lockId, CancellationToken.None)).ReturnsAsync("someotherguy");
            SingletonValueProvider localValueProvider = new SingletonValueProvider(_method, _attribute.ScopeId, TestInstanceId, _attribute, mockSingletonManager.Object);
            SingletonLock          localSingletonLock = (SingletonLock)(await localValueProvider.GetValueAsync());

            // set start time before _minimumWaitForFirstOwnerCheck in SingletonValueProvider
            DateTime startTime   = DateTime.UtcNow - TimeSpan.FromSeconds(11);
            DateTime endTime     = DateTime.UtcNow + TimeSpan.FromSeconds(2);
            DateTime releaseTime = endTime + TimeSpan.FromSeconds(1);

            // before lock is called
            SingletonValueProvider.SingletonWatcher watcher = (SingletonValueProvider.SingletonWatcher)localValueProvider.Watcher;
            SingletonParameterLog log = (SingletonParameterLog)watcher.GetStatus();

            Assert.Null(log.LockOwner);
            Assert.False(log.LockAcquired);
            Assert.Null(log.LockDuration);
            Assert.Null(log.TimeToAcquireLock);

            // in the process of locking
            localSingletonLock.AcquireStartTime = startTime;
            log = (SingletonParameterLog)watcher.GetStatus();
            Assert.Equal("someotherguy", log.LockOwner);
            Assert.False(log.LockAcquired);
            Assert.Null(log.LockDuration);
            Assert.NotNull(log.TimeToAcquireLock);

            // lock acquired but not released
            localSingletonLock.AcquireEndTime = endTime;
            log = (SingletonParameterLog)watcher.GetStatus();
            Assert.Null(log.LockOwner);
            Assert.True(log.LockAcquired);
            Assert.NotNull(log.LockDuration);
            Assert.Equal(endTime - startTime, log.TimeToAcquireLock);

            // lock released
            localSingletonLock.ReleaseTime = releaseTime;
            log = (SingletonParameterLog)watcher.GetStatus();
            Assert.Null(log.LockOwner);
            Assert.True(log.LockAcquired);
            Assert.Equal(releaseTime - endTime, log.LockDuration);
            Assert.Equal(endTime - startTime, log.TimeToAcquireLock);
        }
        public async Task AquireAsync_InvokesSingletonManager_WithExpectedValues()
        {
            CancellationToken cancellationToken = new CancellationToken();
            SingletonAttribute attribute = new SingletonAttribute();
            SingletonManager.SingletonLockHandle handle = new SingletonManager.SingletonLockHandle();

            Mock<SingletonManager> mockSingletonManager = new Mock<SingletonManager>(MockBehavior.Strict);
            mockSingletonManager.Setup(p => p.LockAsync(TestLockId, TestInstanceId, attribute, cancellationToken)).ReturnsAsync(handle);

            SingletonLock singletonLock = new SingletonLock(TestLockId, TestInstanceId, attribute, mockSingletonManager.Object);

            Assert.False(singletonLock.IsHeld);
            await singletonLock.AcquireAsync(cancellationToken);

            Assert.NotNull(singletonLock.AcquireStartTime);
            Assert.NotNull(singletonLock.AcquireEndTime);
            Assert.True(singletonLock.IsHeld);
        }
        private static bool TryGetSingletonLock(IReadOnlyDictionary <string, IValueProvider> parameters, out SingletonLock singleton)
        {
            IValueProvider singletonValueProvider = null;

            singleton = null;
            if (parameters.TryGetValue(SingletonValueProvider.SingletonParameterName, out singletonValueProvider))
            {
                singleton = (SingletonLock)singletonValueProvider.GetValue();
                return(true);
            }

            return(false);
        }
        internal static async Task ExecuteWithWatchersAsync(IFunctionInstance instance,
                                                            IReadOnlyDictionary <string, IValueProvider> parameters,
                                                            TraceWriter traceWriter,
                                                            CancellationTokenSource functionCancellationTokenSource)
        {
            IFunctionInvoker       invoker        = instance.Invoker;
            IReadOnlyList <string> parameterNames = invoker.ParameterNames;
            IDelayedException      delayedBindingException;

            object[] invokeParameters = PrepareParameters(parameterNames, parameters, out delayedBindingException);

            if (delayedBindingException != null)
            {
                // This is done inside a watcher context so that each binding error is publish next to the binding in
                // the parameter status log.
                delayedBindingException.Throw();
            }

            // if the function is a Singleton, aquire the lock
            SingletonLock singleton = null;

            if (TryGetSingletonLock(parameters, out singleton))
            {
                await singleton.AcquireAsync(functionCancellationTokenSource.Token);
            }

            // Create a source specifically for timeouts
            using (CancellationTokenSource timeoutTokenSource = new CancellationTokenSource())
            {
                MethodInfo       method           = instance.FunctionDescriptor.Method;
                TimeoutAttribute timeoutAttribute = TypeUtility.GetHierarchicalAttributeOrNull <TimeoutAttribute>(method);
                bool             throwOnTimeout   = timeoutAttribute == null ? false : timeoutAttribute.ThrowOnTimeout;
                var      timer         = StartFunctionTimeout(instance, timeoutAttribute, timeoutTokenSource, traceWriter);
                TimeSpan timerInterval = timer == null ? TimeSpan.MinValue : TimeSpan.FromMilliseconds(timer.Interval);
                try
                {
                    await InvokeAsync(invoker, invokeParameters, timeoutTokenSource, functionCancellationTokenSource,
                                      throwOnTimeout, timerInterval, instance);
                }
                finally
                {
                    if (timer != null)
                    {
                        timer.Stop();
                        timer.Dispose();
                    }
                }
            }

            // Process any out parameters and persist any pending values.
            // Ensure IValueBinder.SetValue is called in BindStepOrder. This ordering is particularly important for
            // ensuring queue outputs occur last. That way, all other function side-effects are guaranteed to have
            // occurred by the time messages are enqueued.
            string[] parameterNamesInBindOrder = SortParameterNamesInStepOrder(parameters);
            foreach (string name in parameterNamesInBindOrder)
            {
                IValueProvider provider = parameters[name];
                IValueBinder   binder   = provider as IValueBinder;

                if (binder != null)
                {
                    object argument = invokeParameters[GetParameterIndex(parameterNames, name)];

                    try
                    {
                        // This could do complex things that may fail. Catch the exception.
                        await binder.SetValueAsync(argument, functionCancellationTokenSource.Token);
                    }
                    catch (OperationCanceledException)
                    {
                        throw;
                    }
                    catch (Exception exception)
                    {
                        string message = String.Format(CultureInfo.InvariantCulture,
                                                       "Error while handling parameter {0} after function returned:", name);
                        throw new InvalidOperationException(message, exception);
                    }
                }
            }

            if (singleton != null)
            {
                await singleton.ReleaseAsync(functionCancellationTokenSource.Token);
            }
        }
        private async Task <string> ExecuteWithLoggingAsync(IFunctionInstance instance, FunctionStartedMessage message,
                                                            FunctionInstanceLogEntry fastItem,
                                                            IDictionary <string, ParameterLog> parameterLogCollector, TraceLevel functionTraceLevel, CancellationToken cancellationToken)
        {
            IFunctionOutputDefinition outputDefinition     = null;
            IFunctionOutput           outputLog            = null;
            ITaskSeriesTimer          updateOutputLogTimer = null;
            TextWriter functionOutputTextWriter            = null;

            Func <Task> initializeOutputAsync = async() =>
            {
                outputDefinition = await _functionOutputLogger.CreateAsync(instance, cancellationToken);

                outputLog = outputDefinition.CreateOutput();
                functionOutputTextWriter = outputLog.Output;
                updateOutputLogTimer     = StartOutputTimer(outputLog.UpdateCommand, _exceptionHandler);
            };

            if (functionTraceLevel >= TraceLevel.Info)
            {
                await initializeOutputAsync();
            }

            try
            {
                // Create a linked token source that will allow us to signal function cancellation
                // (e.g. Based on TimeoutAttribute, etc.)
                CancellationTokenSource functionCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                using (functionCancellationTokenSource)
                {
                    // We create a new composite trace writer that will also forward
                    // output to the function output log (in addition to console, user TraceWriter, etc.).
                    TraceWriter traceWriter = new CompositeTraceWriter(_trace, functionOutputTextWriter, functionTraceLevel);

                    // Must bind before logging (bound invoke string is included in log message).
                    FunctionBindingContext functionContext = new FunctionBindingContext(instance.Id, functionCancellationTokenSource.Token, traceWriter);
                    var valueBindingContext = new ValueBindingContext(functionContext, cancellationToken);
                    var parameters          = await instance.BindingSource.BindAsync(valueBindingContext);

                    Exception             invocationException = null;
                    ExceptionDispatchInfo exceptionInfo       = null;
                    string startedMessageId = null;
                    using (ValueProviderDisposable.Create(parameters))
                    {
                        if (functionTraceLevel >= TraceLevel.Info)
                        {
                            startedMessageId = await LogFunctionStartedAsync(message, outputDefinition, parameters, cancellationToken);
                        }

                        if (_fastLogger != null)
                        {
                            // Log started
                            fastItem.Arguments = message.Arguments;
                            await _fastLogger.AddAsync(fastItem);
                        }

                        try
                        {
                            await ExecuteWithLoggingAsync(instance, parameters, traceWriter, outputDefinition, parameterLogCollector, functionTraceLevel, functionCancellationTokenSource);
                        }
                        catch (Exception ex)
                        {
                            invocationException = ex;
                        }
                    }

                    if (invocationException != null)
                    {
                        if (outputDefinition == null)
                        {
                            // In error cases, even if logging is disabled for this function, we want to force
                            // log errors. So we must delay initialize logging here
                            await initializeOutputAsync();

                            startedMessageId = await LogFunctionStartedAsync(message, outputDefinition, parameters, cancellationToken);
                        }

                        // In the event of cancellation or timeout, we use the original exception without additional logging.
                        if (invocationException is OperationCanceledException || invocationException is FunctionTimeoutException)
                        {
                            exceptionInfo = ExceptionDispatchInfo.Capture(invocationException);
                        }
                        else
                        {
                            string errorMessage             = string.Format("Exception while executing function: {0}", instance.FunctionDescriptor.ShortName);
                            FunctionInvocationException fex = new FunctionInvocationException(errorMessage, instance.Id, instance.FunctionDescriptor.FullName, invocationException);
                            traceWriter.Error(errorMessage, fex, TraceSource.Execution);
                            exceptionInfo = ExceptionDispatchInfo.Capture(fex);
                        }
                    }

                    if (exceptionInfo == null && updateOutputLogTimer != null)
                    {
                        await updateOutputLogTimer.StopAsync(cancellationToken);
                    }

                    // after all execution is complete, flush the TraceWriter
                    traceWriter.Flush();

                    // We save the exception info above rather than throwing to ensure we always write
                    // console output even if the function fails or was canceled.
                    if (outputLog != null)
                    {
                        await outputLog.SaveAndCloseAsync(fastItem, cancellationToken);
                    }

                    if (exceptionInfo != null)
                    {
                        // release any held singleton lock immediately
                        SingletonLock singleton = null;
                        if (TryGetSingletonLock(parameters, out singleton) && singleton.IsHeld)
                        {
                            await singleton.ReleaseAsync(cancellationToken);
                        }

                        exceptionInfo.Throw();
                    }

                    return(startedMessageId);
                }
            }
            finally
            {
                if (outputLog != null)
                {
                    ((IDisposable)outputLog).Dispose();
                }
                if (updateOutputLogTimer != null)
                {
                    ((IDisposable)updateOutputLogTimer).Dispose();
                }
            }
        }
예제 #19
0
        private async Task <string> ExecuteWithLogMessageAsync(IFunctionInstance instance, FunctionStartedMessage message,
                                                               IDictionary <string, ParameterLog> parameterLogCollector, CancellationToken cancellationToken)
        {
            string startedMessageId;

            // Create the console output writer
            IFunctionOutputDefinition outputDefinition = await _functionOutputLogger.CreateAsync(instance, cancellationToken);

            // Create a linked token source that will allow us to signal function cancellation
            // (e.g. Based on TimeoutAttribute, etc.)
            CancellationTokenSource functionCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

            using (IFunctionOutput outputLog = await outputDefinition.CreateOutputAsync(cancellationToken))
                using (ITaskSeriesTimer updateOutputLogTimer = StartOutputTimer(outputLog.UpdateCommand, _backgroundExceptionDispatcher))
                    using (functionCancellationTokenSource)
                    {
                        // We create a new composite trace writer that will also forward
                        // output to the function output log (in addition to console, user TraceWriter, etc.).
                        TraceWriter traceWriter = new CompositeTraceWriter(_trace, outputLog.Output);

                        FunctionBindingContext functionContext = new FunctionBindingContext(instance.Id, functionCancellationTokenSource.Token, traceWriter);

                        // Must bind before logging (bound invoke string is included in log message).
                        IReadOnlyDictionary <string, IValueProvider> parameters =
                            await instance.BindingSource.BindAsync(new ValueBindingContext(functionContext, cancellationToken));

                        ExceptionDispatchInfo exceptionInfo;
                        using (ValueProviderDisposable.Create(parameters))
                        {
                            startedMessageId = await LogFunctionStartedAsync(message, outputDefinition, parameters, cancellationToken);

                            try
                            {
                                await ExecuteWithOutputLogsAsync(instance, parameters, traceWriter, outputDefinition, parameterLogCollector, functionCancellationTokenSource);

                                exceptionInfo = null;
                            }
                            catch (OperationCanceledException exception)
                            {
                                exceptionInfo = ExceptionDispatchInfo.Capture(exception);
                            }
                            catch (Exception exception)
                            {
                                string errorMessage = string.Format("Exception while executing function: {0}", instance.FunctionDescriptor.ShortName);
                                FunctionInvocationException functionException = new FunctionInvocationException(errorMessage, instance.Id, instance.FunctionDescriptor.FullName, exception);
                                traceWriter.Error(errorMessage, functionException, TraceSource.Execution);
                                exceptionInfo = ExceptionDispatchInfo.Capture(functionException);
                            }
                        }

                        if (exceptionInfo == null && updateOutputLogTimer != null)
                        {
                            await updateOutputLogTimer.StopAsync(cancellationToken);
                        }

                        // after all execution is complete, flush the TraceWriter
                        traceWriter.Flush();

                        // We save the exception info rather than doing throw; above to ensure we always write console output,
                        // even if the function fails or was canceled.
                        await outputLog.SaveAndCloseAsync(cancellationToken);

                        if (exceptionInfo != null)
                        {
                            // release any held singleton lock immediately
                            SingletonLock singleton = null;
                            if (TryGetSingletonLock(parameters, out singleton) && singleton.IsHeld)
                            {
                                await singleton.ReleaseAsync(cancellationToken);
                            }

                            exceptionInfo.Throw();
                        }

                        return(startedMessageId);
                    }
        }
예제 #20
0
        internal static async Task ExecuteWithWatchersAsync(IFunctionInvoker invoker,
                                                            IReadOnlyDictionary <string, IValueProvider> parameters,
                                                            CancellationToken cancellationToken)
        {
            IReadOnlyList <string> parameterNames = invoker.ParameterNames;
            IDelayedException      delayedBindingException;

            object[] invokeParameters = PrepareParameters(parameterNames, parameters, out delayedBindingException);

            if (delayedBindingException != null)
            {
                // This is done inside a watcher context so that each binding error is publish next to the binding in
                // the parameter status log.
                delayedBindingException.Throw();
            }

            // if the function is a Singleton, aquire the lock
            SingletonLock singleton = null;

            if (TryGetSingletonLock(parameters, out singleton))
            {
                await singleton.AcquireAsync(cancellationToken);
            }

            // Cancellation token is provide by invokeParameters (if the method binds to CancellationToken).
            await invoker.InvokeAsync(invokeParameters);

            // Process any out parameters and persist any pending values.
            // Ensure IValueBinder.SetValue is called in BindOrder. This ordering is particularly important for
            // ensuring queue outputs occur last. That way, all other function side-effects are guaranteed to have
            // occurred by the time messages are enqueued.
            string[] parameterNamesInBindOrder = SortParameterNamesInStepOrder(parameters);
            foreach (string name in parameterNamesInBindOrder)
            {
                IValueProvider provider = parameters[name];
                IValueBinder   binder   = provider as IValueBinder;

                if (binder != null)
                {
                    object argument = invokeParameters[GetParameterIndex(parameterNames, name)];

                    try
                    {
                        // This could do complex things that may fail. Catch the exception.
                        await binder.SetValueAsync(argument, cancellationToken);
                    }
                    catch (OperationCanceledException)
                    {
                        throw;
                    }
                    catch (Exception exception)
                    {
                        string message = String.Format(CultureInfo.InvariantCulture,
                                                       "Error while handling parameter {0} after function returned:", name);
                        throw new InvalidOperationException(message, exception);
                    }
                }
            }

            if (singleton != null)
            {
                await singleton.ReleaseAsync(cancellationToken);
            }
        }