Example #1
0
        /// <summary>
        /// Using a filter-supplied context type, block so that the one time code is only executed once regardless of how many
        /// threads are pushing through the pipe at the same time.
        /// </summary>
        /// <typeparam name="T">The payload type, should be an interface</typeparam>
        /// <param name="context">The pipe context</param>
        /// <param name="setupMethod">The setup method, called once regardless of the thread count</param>
        /// <param name="payloadFactory">The factory method for the payload context, optional if an interface is specified</param>
        /// <returns></returns>
        public static async Task OneTimeSetup <T>(this PipeContext context, Func <T, Task> setupMethod, PayloadFactory <T> payloadFactory = null)
            where T : class
        {
            OneTime <T> newContext      = null;
            var         existingContext = context.GetOrAddPayload <OneTimeSetupContext <T> >(() =>
            {
                var payload = payloadFactory?.Invoke() ?? TypeMetadataCache <T> .InitializeFromObject(new {});

                newContext = new OneTime <T>(payload);

                return(newContext);
            });

            if (newContext == existingContext)
            {
                try
                {
                    await setupMethod(newContext.Payload).ConfigureAwait(false);

                    newContext.SetReady();
                }
                catch (Exception exception)
                {
                    newContext.SetFaulted(exception);

                    throw;
                }
            }
            else
            {
                await existingContext.Ready.ConfigureAwait(false);
            }
        }