public Func <IChangeToken> Build(out IDisposable factoryLifetime) { var disposables = _disposables.ToArray(); // capture snapshot. factoryLifetime = new InvokeOnDispose(() => { foreach (var item in disposables) { item?.Dispose(); } }); if (Factories == null || Factories.Count == 0) { return(() => EmptyChangeToken.Instance); } if (Factories.Count == 1) { return(Factories[0]); // pass through - no need to build composite for single producer. } var factories = Factories.ToArray(); // capture snapshot Reset(); // so builder is empty again to build another. return(() => { var tokens = new IChangeToken[factories.Length]; for (var i = 0; i < factories.Length; i++) { tokens[i] = factories[i].Invoke(); } return new CompositeChangeToken(tokens); }); }
/// <summary> /// Adds <see cref="ReloadPipelineMiddleware"/> to the middleware pipeline, with a change token to invalidate it and rebuild it whenever <typeparamref name="TOptions"/> changes. /// </summary> /// <typeparam name="TOptions"></typeparam> /// <param name="builder"></param> /// <param name="configure"></param> /// <param name="isTerminal"></param> /// <returns></returns> /// <remarks>You must ensure <typeparamref name="TOptions"/></remarks> has been registered with the options system in ConfigureServices. private static IApplicationBuilder AddReloadablePipeline <TOptions>(this IApplicationBuilder builder, Action <IApplicationBuilder, IWebHostEnvironment, TOptions> configure, bool isTerminal) where TOptions : class { var env = builder.ApplicationServices.GetRequiredService <IWebHostEnvironment>(); var monitor = builder.ApplicationServices.GetRequiredService <IOptionsMonitor <TOptions> >(); IDisposable previousRegistration = null; var factory = new RequestDelegateFactory(env, () => { // When should ensure any previous CancellationTokenSource is disposed, // and we remove old monitor OnChange listener, before creating new ones. previousRegistration?.Dispose(); var changeTokenSource = new CancellationTokenSource(); var monitorListener = monitor.OnChange(a => changeTokenSource.Cancel()); previousRegistration = new InvokeOnDispose(() => { // Ensure disposal of listener and token source that we created. monitorListener.Dispose(); changeTokenSource.Dispose(); }); var changeToken = new CancellationChangeToken(changeTokenSource.Token); return(changeToken); }, (a, b) => { configure(a, b, monitor.CurrentValue); }); builder.UseMiddleware <ReloadPipelineMiddleware>(builder, factory, isTerminal); return(builder); }
public static Func <IChangeToken> UseCallbackRegistrations(Func <Action, IDisposable> registerListener) { IDisposable previousRegistration = null; Func <IChangeToken> changeTokenFactory = () => { // When should ensure any previous CancellationTokenSource is disposed, // and we remove old monitor OnChange listener, before creating new ones. previousRegistration?.Dispose(); var changeTokenSource = new CancellationTokenSource(); var disposable = registerListener(() => changeTokenSource.Cancel()); previousRegistration = new InvokeOnDispose(() => { // Ensure disposal of listener and token source that we created. disposable.Dispose(); changeTokenSource.Dispose(); }); var changeToken = new CancellationChangeToken(changeTokenSource.Token); return(changeToken); }; return(changeTokenFactory); }