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);
        }
Exemplo n.º 3
0
        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);
        }