private void UpdateRuntimeRoutes(DynamicConfigRoot config) { var desiredRoutes = new HashSet <string>(StringComparer.Ordinal); var changed = false; foreach (var configRoute in config.Routes) { desiredRoutes.Add(configRoute.RouteId); // Note that this can be null, and that is fine. The resulting route may match // but would then fail to route, which is exactly what we were instructed to do in this case // since no valid backend was specified. var backendOrNull = _backendManager.TryGetItem(configRoute.BackendId); _routeManager.GetOrCreateItem( itemId: configRoute.RouteId, setupAction: route => { var currentRouteConfig = route.Config.Value; if (currentRouteConfig == null || currentRouteConfig.HasConfigChanged(configRoute, backendOrNull)) { // Config changed, so update runtime route changed = true; if (currentRouteConfig == null) { _logger.LogDebug("Route {routeId} has been added.", configRoute.RouteId); } else { _logger.LogDebug("Route {routeId} has changed.", configRoute.RouteId); } var newConfig = _routeEndpointBuilder.Build(configRoute, backendOrNull, route); route.Config.Value = newConfig; } }); } foreach (var existingRoute in _routeManager.GetItems()) { if (!desiredRoutes.Contains(existingRoute.RouteId)) { // NOTE 1: This is safe to do within the `foreach` loop // because `IRouteManager.GetItems` returns a copy of the list of routes. // // NOTE 2: Removing the route from `IRouteManager` is safe and existing // ASP .NET Core endpoints will continue to work with their existing behavior since // their copy of `RouteConfig` is immutable and remains operational in whichever state is was in. _logger.LogDebug("Route {routeId} has been removed.", existingRoute.RouteId); _routeManager.TryRemoveItem(existingRoute.RouteId); changed = true; } } if (changed) { var aspNetCoreEndpoints = new List <AspNetCore.Http.Endpoint>(); foreach (var existingRoute in _routeManager.GetItems()) { var runtimeConfig = existingRoute.Config.Value; if (runtimeConfig?.AspNetCoreEndpoints != null) { aspNetCoreEndpoints.AddRange(runtimeConfig.AspNetCoreEndpoints); } } // This is where the new routes take effect! _dynamicEndpointDataSource.Update(aspNetCoreEndpoints); } }