// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Reflection; namespace Microsoft.Extensions.Hosting { internal class HostFactoryResolver { public static readonly string BuildWebHost = nameof(BuildWebHost); public static readonly string CreateWebHostBuilder = nameof(CreateWebHostBuilder); public static readonly string CreateHostBuilder = nameof(CreateHostBuilder); public static Func ResolveWebHostFactory(Assembly assembly) { return ResolveFactory(assembly, BuildWebHost); } public static Func ResolveWebHostBuilderFactory(Assembly assembly) { return ResolveFactory(assembly, CreateWebHostBuilder); } public static Func ResolveHostBuilderFactory(Assembly assembly) { return ResolveFactory(assembly, CreateHostBuilder); } private static Func ResolveFactory(Assembly assembly, string name) { var programType = assembly?.EntryPoint?.DeclaringType; if (programType == null) { return null; } var factory = programType.GetTypeInfo().GetDeclaredMethod(name); if (!IsFactory(factory)) { return null; } return args => (T)factory.Invoke(null, new object[] { args }); } // TReturn Factory(string[] args); private static bool IsFactory(MethodInfo factory) { return factory != null && typeof(TReturn).IsAssignableFrom(factory.ReturnType) && factory.GetParameters().Length == 1 && typeof(string[]).Equals(factory.GetParameters()[0].ParameterType); } // Used by EF tooling without any Hosting references. Looses some return type safety checks. public static Func ResolveServiceProviderFactory(Assembly assembly) { // Prefer the older patterns by default for back compat. var webHostFactory = ResolveWebHostFactory(assembly); if (webHostFactory != null) { return args => { var webHost = webHostFactory(args); return GetServiceProvider(webHost); }; } var webHostBuilderFactory = ResolveWebHostBuilderFactory(assembly); if (webHostBuilderFactory != null) { return args => { var webHostBuilder = webHostBuilderFactory(args); var webHost = Build(webHostBuilder); return GetServiceProvider(webHost); }; } var hostBuilderFactory = ResolveHostBuilderFactory(assembly); if (hostBuilderFactory != null) { return args => { var hostBuilder = hostBuilderFactory(args); var host = Build(hostBuilder); return GetServiceProvider(host); }; } return null; } private static object Build(object builder) { var buildMethod = builder.GetType().GetMethod("Build"); return buildMethod?.Invoke(builder, Array.Empty()); } private static IServiceProvider GetServiceProvider(object host) { if (host == null) { return null; } var hostType = host.GetType(); var servicesProperty = hostType.GetTypeInfo().GetDeclaredProperty("Services"); return (IServiceProvider)servicesProperty.GetValue(host); } } }