private void ValidateBundleRequirements(ExtensionBundleDetails bundleDetails)
        {
            if (_extensionRequirements.BundleRequirementsByBundleId.TryGetValue(bundleDetails.Id, out BundleRequirement requirement))
            {
                var bundleVersion  = new Version(bundleDetails.Version);
                var minimumVersion = new Version(requirement.MinimumVersion);

                if (bundleVersion < minimumVersion)
                {
                    _logger.MinimumBundleVersionNotSatisfied(bundleDetails.Id, bundleDetails.Version, requirement.MinimumVersion);
                    throw new HostInitializationException($"Referenced bundle {bundleDetails.Id} of version {bundleDetails.Version} does not meet the required minimum version of {requirement.MinimumVersion}. Update your extension bundle reference in host.json to reference {requirement.MinimumVersion} or later. For more information see https://aka.ms/func-min-bundle-versions.");
                }
            }
        }
        public async Task <IEnumerable <Type> > GetExtensionsStartupTypesAsync()
        {
            string extensionsMetadataPath;

            FunctionAssemblyLoadContext.ResetSharedContext();

            HashSet <string> bindingsSet  = null;
            var  bundleConfigured         = _extensionBundleManager.IsExtensionBundleConfigured();
            bool isLegacyExtensionBundle  = _extensionBundleManager.IsLegacyExtensionBundle();
            bool isPrecompiledFunctionApp = false;

            // if workerIndexing
            //      Function.json (httpTrigger, blobTrigger, blobTrigger)  -> httpTrigger, blobTrigger
            // dotnet app precompiled -> Do not use bundles
            var workerConfigs = _languageWorkerOptions.Value.WorkerConfigs;

            if (bundleConfigured && !Utility.CanWorkerIndex(workerConfigs, SystemEnvironment.Instance))
            {
                ExtensionBundleDetails bundleDetails = await _extensionBundleManager.GetExtensionBundleDetails();

                ValidateBundleRequirements(bundleDetails);

                var functionMetadataCollection = _functionMetadataManager.GetFunctionMetadata(forceRefresh: true, includeCustomProviders: false);
                bindingsSet = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

                // Generate a Hashset of all the binding types used in the function app
                foreach (var functionMetadata in functionMetadataCollection)
                {
                    foreach (var binding in functionMetadata.Bindings)
                    {
                        bindingsSet.Add(binding.Type);
                    }
                    isPrecompiledFunctionApp = isPrecompiledFunctionApp || functionMetadata.Language == DotNetScriptTypes.DotNetAssembly;
                }
            }

            if (SystemEnvironment.Instance.IsPlaceholderModeEnabled())
            {
                // Do not move this.
                // Calling this log statement in the placeholder mode to avoid jitting during specializtion
                _logger.ScriptStartNotLoadingExtensionBundle("WARMUP_LOG_ONLY", bundleConfigured, isPrecompiledFunctionApp, isLegacyExtensionBundle);
            }

            string baseProbingPath = null;

            if (bundleConfigured && (!isPrecompiledFunctionApp || isLegacyExtensionBundle))
            {
                extensionsMetadataPath = await _extensionBundleManager.GetExtensionBundleBinPathAsync();

                if (string.IsNullOrEmpty(extensionsMetadataPath))
                {
                    _logger.ScriptStartUpErrorLoadingExtensionBundle();
                    return(Array.Empty <Type>());
                }

                _logger.ScriptStartUpLoadingExtensionBundle(extensionsMetadataPath);
            }
            else
            {
                extensionsMetadataPath = Path.Combine(_rootScriptPath, "bin");

                // Verify if the file exists and apply fallback paths
                // The fallback order is:
                //   1 - Script root
                //       - If the system folder exists with metadata file at the root, use that as the base probing path
                //   2 - System folder
                if (!File.Exists(Path.Combine(extensionsMetadataPath, ScriptConstants.ExtensionsMetadataFileName)))
                {
                    string systemPath = Path.Combine(_rootScriptPath, ScriptConstants.AzureFunctionsSystemDirectoryName);

                    if (File.Exists(Path.Combine(_rootScriptPath, ScriptConstants.ExtensionsMetadataFileName)))
                    {
                        // As a fallback, allow extensions.json in the root path.
                        extensionsMetadataPath = _rootScriptPath;

                        // If the system path exists, that should take precedence as the base probing path
                        if (Directory.Exists(systemPath))
                        {
                            baseProbingPath = systemPath;
                        }
                    }
                    else if (File.Exists(Path.Combine(systemPath, ScriptConstants.ExtensionsMetadataFileName)))
                    {
                        extensionsMetadataPath = systemPath;
                    }
                }

                _logger.ScriptStartNotLoadingExtensionBundle(extensionsMetadataPath, bundleConfigured, isPrecompiledFunctionApp, isLegacyExtensionBundle);
            }

            baseProbingPath ??= extensionsMetadataPath;
            _logger.ScriptStartupResettingLoadContextWithBasePath(baseProbingPath);

            // Reset the load context using the resolved extensions path
            FunctionAssemblyLoadContext.ResetSharedContext(baseProbingPath);

            string metadataFilePath = Path.Combine(extensionsMetadataPath, ScriptConstants.ExtensionsMetadataFileName);

            // parse the extensions file to get declared startup extensions
            ExtensionReference[] extensionItems = ParseExtensions(metadataFilePath);

            var startupTypes = new List <Type>();

            foreach (var extensionItem in extensionItems)
            {
                // We need to explicitly ignore ApplicationInsights extension
                if (extensionItem.TypeName.Equals(ApplicationInsightsStartupType, StringComparison.Ordinal))
                {
                    _logger.LogWarning("The Application Insights extension is no longer supported. Package references to Microsoft.Azure.WebJobs.Extensions.ApplicationInsights can be removed.");
                    continue;
                }

                if (Utility.CanWorkerIndex(workerConfigs, SystemEnvironment.Instance) ||
                    !bundleConfigured ||
                    extensionItem.Bindings.Count == 0 ||
                    extensionItem.Bindings.Intersect(bindingsSet, StringComparer.OrdinalIgnoreCase).Any())
                {
                    string startupExtensionName = extensionItem.Name ?? extensionItem.TypeName;
                    _logger.ScriptStartUpLoadingStartUpExtension(startupExtensionName);

                    // load the Type for each startup extension into the function assembly load context
                    Type extensionType = Type.GetType(extensionItem.TypeName,
                                                      assemblyName =>
                    {
                        if (_builtinExtensionAssemblies.Contains(assemblyName.Name, StringComparer.OrdinalIgnoreCase))
                        {
                            _logger.ScriptStartUpBelongExtension(extensionItem.TypeName);
                            return(null);
                        }

                        string path = extensionItem.HintPath;
                        if (string.IsNullOrEmpty(path))
                        {
                            path = assemblyName.Name + ".dll";
                        }

                        var hintUri = new Uri(path, UriKind.RelativeOrAbsolute);
                        if (!hintUri.IsAbsoluteUri)
                        {
                            path = Path.Combine(extensionsMetadataPath, path);
                        }

                        if (File.Exists(path))
                        {
                            return(FunctionAssemblyLoadContext.Shared.LoadFromAssemblyPath(path, true));
                        }

                        return(null);
                    },
                                                      (assembly, typeName, ignoreCase) =>
                    {
                        _logger.ScriptStartUpLoadedExtension(startupExtensionName, assembly.GetName().Version.ToString());
                        return(assembly?.GetType(typeName, false, ignoreCase));
                    }, false, true);

                    if (extensionType == null)
                    {
                        _logger.ScriptStartUpUnableToLoadExtension(startupExtensionName, extensionItem.TypeName);
                        continue;
                    }

                    if (!typeof(IWebJobsStartup).IsAssignableFrom(extensionType) && !typeof(IWebJobsConfigurationStartup).IsAssignableFrom(extensionType))
                    {
                        _logger.ScriptStartUpTypeIsNotValid(extensionItem.TypeName, nameof(IWebJobsStartup), nameof(IWebJobsConfigurationStartup));
                        continue;
                    }

                    startupTypes.Add(extensionType);
                }
            }

            ValidateExtensionRequirements(startupTypes);

            return(startupTypes);
        }