/// <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); } }