/// <summary>
        /// Adds isolated tenant level routing services.
        /// </summary>
        private static void AddRouting(OrchardCoreBuilder builder)
        {
            // 'AddRouting()' is called by the host.

            builder.ConfigureServices(collection =>
            {
                // The routing system is not tenant aware and uses a global list of endpoint data sources which is
                // setup by the default configuration of 'RouteOptions' and mutated on each call of 'UseEndPoints()'.
                // So, we need isolated routing singletons (and a default configuration) per tenant.

                var implementationTypesToRemove = new ServiceCollection().AddRouting()
                                                  .Where(sd => sd.Lifetime == ServiceLifetime.Singleton || sd.ServiceType == typeof(IConfigureOptions <RouteOptions>))
                                                  .Select(sd => sd.GetImplementationType())
                                                  .ToArray();

                var descriptorsToRemove = collection
                                          .Where(sd => (sd is ClonedSingletonDescriptor || sd.ServiceType == typeof(IConfigureOptions <RouteOptions>)) &&
                                                 implementationTypesToRemove.Contains(sd.GetImplementationType()))
                                          .ToArray();

                foreach (var descriptor in descriptorsToRemove)
                {
                    collection.Remove(descriptor);
                }

                collection.AddRouting();
            },
                                      order: Int32.MinValue + 100);
        }
        public void TestMakeReadOnly()
        {
            var serviceCollection = new ServiceCollection();
            var descriptor        = new ServiceDescriptor(typeof(IFakeService), new FakeService());

            serviceCollection.Add(descriptor);

            serviceCollection.MakeReadOnly();

            var descriptor2 = new ServiceDescriptor(typeof(IFakeEveryService), new FakeService());

            Assert.Throws <InvalidOperationException>(() => serviceCollection[0] = descriptor2);
            Assert.Throws <InvalidOperationException>(() => serviceCollection.Clear());
            Assert.Throws <InvalidOperationException>(() => serviceCollection.Remove(descriptor));
            Assert.Throws <InvalidOperationException>(() => serviceCollection.Add(descriptor2));
            Assert.Throws <InvalidOperationException>(() => serviceCollection.Insert(0, descriptor2));
            Assert.Throws <InvalidOperationException>(() => serviceCollection.RemoveAt(0));

            Assert.True(serviceCollection.IsReadOnly);
            Assert.Equal(1, serviceCollection.Count);
            foreach (ServiceDescriptor d in serviceCollection)
            {
                Assert.Equal(descriptor, d);
            }
            Assert.Equal(descriptor, serviceCollection[0]);
            Assert.True(serviceCollection.Contains(descriptor));
            Assert.Equal(0, serviceCollection.IndexOf(descriptor));

            ServiceDescriptor[] copyArray = new ServiceDescriptor[1];
            serviceCollection.CopyTo(copyArray, 0);
            Assert.Equal(descriptor, copyArray[0]);

            // ensure MakeReadOnly can be called twice, and it is just ignored
            serviceCollection.MakeReadOnly();
            Assert.True(serviceCollection.IsReadOnly);
        }