Supporting Startup method dependency injection

also changes method name from Configuration to Configure
also supports enviroment name command line and
This commit is contained in:
Louis DeJardin 2014-05-08 20:38:36 -07:00
parent e8ce130315
commit 55271e8719
10 changed files with 96 additions and 34 deletions

View File

@ -18,18 +18,19 @@
using Microsoft.AspNet; using Microsoft.AspNet;
using Microsoft.AspNet.Builder; using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.Framework.Runtime;
namespace KWebStartup namespace KWebStartup
{ {
public class Startup public class Startup
{ {
public void Configuration(IBuilder app) public void Configure(IBuilder app, IApplicationEnvironment env)
{ {
app.Run(async context => app.Run(async context =>
{ {
context.Response.ContentType = "text/plain"; context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello world"); await context.Response.WriteAsync("Hello world, from " + env.ApplicationName);
}); });
} }
} }
} }

View File

@ -5,7 +5,7 @@
"Microsoft.AspNet.Http": "0.1-alpha-*", "Microsoft.AspNet.Http": "0.1-alpha-*",
"Microsoft.AspNet.Server.WebListener": "0.1-alpha-*" "Microsoft.AspNet.Server.WebListener": "0.1-alpha-*"
}, },
"commands": { "web": "Microsoft.AspNet.Hosting server.name=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001" }, "commands": { "web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001" },
"configurations": { "configurations": {
"net45": { "net45": {
}, },

View File

@ -31,6 +31,7 @@ namespace Microsoft.AspNet.Hosting
public IBuilder Builder { get; set; } public IBuilder Builder { get; set; }
public string ApplicationName { get; set; } public string ApplicationName { get; set; }
public string EnvironmentName { get; set; }
public Action<IBuilder> ApplicationStartup { get; set; } public Action<IBuilder> ApplicationStartup { get; set; }
public RequestDelegate ApplicationDelegate { get; set; } public RequestDelegate ApplicationDelegate { get; set; }

View File

@ -117,7 +117,9 @@ namespace Microsoft.AspNet.Hosting
return; return;
} }
context.ApplicationStartup = _startupManager.LoadStartup(context.ApplicationName); context.ApplicationStartup = _startupManager.LoadStartup(
context.ApplicationName,
context.EnvironmentName);
} }
private class Disposable : IDisposable private class Disposable : IDisposable

View File

@ -38,12 +38,12 @@ namespace Microsoft.AspNet.Hosting
public void Main(string[] args) public void Main(string[] args)
{ {
var config = new Configuration(); var config = new Configuration();
config.AddCommandLine(args);
if (File.Exists(HostingIniFile)) if (File.Exists(HostingIniFile))
{ {
config.AddIniFile(HostingIniFile); config.AddIniFile(HostingIniFile);
} }
config.AddEnvironmentVariables(); config.AddEnvironmentVariables();
config.AddCommandLine(args);
var serviceCollection = new ServiceCollection(); var serviceCollection = new ServiceCollection();
serviceCollection.Add(HostingServices.GetDefaultServices(config)); serviceCollection.Add(HostingServices.GetDefaultServices(config));
@ -55,9 +55,10 @@ namespace Microsoft.AspNet.Hosting
{ {
Services = services, Services = services,
Configuration = config, Configuration = config,
ServerName = config.Get("server.name"), // TODO: Key names ServerName = config.Get("server"), // TODO: Key names
ApplicationName = config.Get("app.name") // TODO: Key names ApplicationName = config.Get("app") // TODO: Key names
?? appEnvironment.ApplicationName, ?? appEnvironment.ApplicationName,
EnvironmentName = config.Get("env") ?? "Development"
}; };
var engine = services.GetService<IHostingEngine>(); var engine = services.GetService<IHostingEngine>();

View File

@ -24,6 +24,9 @@ namespace Microsoft.AspNet.Hosting.Startup
{ {
public interface IStartupLoader public interface IStartupLoader
{ {
Action<IBuilder> LoadStartup(string applicationName, IList<string> diagnosticMessages); Action<IBuilder> LoadStartup(
string applicationName,
string environmentName,
IList<string> diagnosticMessages);
} }
} }

View File

@ -23,6 +23,8 @@ namespace Microsoft.AspNet.Hosting.Startup
{ {
public interface IStartupManager public interface IStartupManager
{ {
Action<IBuilder> LoadStartup(string applicationName); Action<IBuilder> LoadStartup(
string applicationName,
string environmentName);
} }
} }

View File

@ -31,7 +31,10 @@ namespace Microsoft.AspNet.Hosting.Startup
public static IStartupLoader Instance { get; private set; } public static IStartupLoader Instance { get; private set; }
public Action<IBuilder> LoadStartup(string applicationName, IList<string> diagnosticMessages) public Action<IBuilder> LoadStartup(
string applicationName,
string environmentName,
IList<string> diagnosticMessages)
{ {
return null; return null;
} }

View File

@ -30,42 +30,49 @@ namespace Microsoft.AspNet.Hosting.Startup
private readonly IServiceProvider _services; private readonly IServiceProvider _services;
private readonly IStartupLoader _next; private readonly IStartupLoader _next;
public StartupLoader(IServiceProvider services, IStartupLoader next) public StartupLoader(
IServiceProvider services,
IStartupLoader next)
{ {
_services = services; _services = services;
_next = next; _next = next;
} }
public Action<IBuilder> LoadStartup(string applicationName, IList<string> diagnosticMessages) public Action<IBuilder> LoadStartup(
string applicationName,
string environmentName,
IList<string> diagnosticMessages)
{ {
if (String.IsNullOrEmpty(applicationName)) if (String.IsNullOrEmpty(applicationName))
{ {
return _next.LoadStartup(applicationName, diagnosticMessages); return _next.LoadStartup(applicationName, environmentName, diagnosticMessages);
} }
var nameParts = Utilities.SplitTypeName(applicationName); var assembly = Assembly.Load(new AssemblyName(applicationName));
string typeName = nameParts.Item1;
string assemblyName = nameParts.Item2;
var assembly = Assembly.Load(new AssemblyName(assemblyName));
if (assembly == null) if (assembly == null)
{ {
throw new Exception(String.Format("TODO: assembly {0} failed to load message", assemblyName)); throw new Exception(String.Format("TODO: assembly {0} failed to load message", applicationName));
} }
Type type = null; var startupName1 = "Startup" + environmentName;
if (string.IsNullOrEmpty(typeName)) var startupName2 = "Startup";
{
typeName = "Startup";
}
// Check the most likely places first // Check the most likely places first
type = assembly.GetType(typeName) ?? assembly.GetType(assembly.GetName().Name + "." + typeName); var type =
assembly.GetType(startupName1) ??
assembly.GetType(applicationName + "." + startupName1) ??
assembly.GetType(startupName2) ??
assembly.GetType(applicationName + "." + startupName2);
if (type == null) if (type == null)
{ {
// Full scan // Full scan
var typeInfo = assembly.DefinedTypes.FirstOrDefault(aType => aType.Name.Equals(typeName, StringComparison.OrdinalIgnoreCase)); var definedTypes = assembly.DefinedTypes.ToList();
var startupType1 = definedTypes.Where(info => info.Name.Equals(startupName1, StringComparison.Ordinal));
var startupType2 = definedTypes.Where(info => info.Name.Equals(startupName2, StringComparison.Ordinal));
var typeInfo = startupType1.Concat(startupType2).FirstOrDefault();
if (typeInfo != null) if (typeInfo != null)
{ {
type = typeInfo.AsType(); type = typeInfo.AsType();
@ -74,18 +81,30 @@ namespace Microsoft.AspNet.Hosting.Startup
if (type == null) if (type == null)
{ {
throw new Exception(String.Format("TODO: type {0} failed to load message", typeName)); throw new Exception(String.Format("TODO: {0} or {1} class not found in assembly {2}",
startupName1,
startupName2,
applicationName));
} }
var methodInfo = type.GetTypeInfo().GetDeclaredMethod("Configuration"); var configureMethod1 = "Configure" + environmentName;
var configureMethod2 = "Configure";
var methodInfo = type.GetTypeInfo().GetDeclaredMethod(configureMethod1);
if (methodInfo == null) if (methodInfo == null)
{ {
throw new Exception("TODO: Configuration method not found"); methodInfo = type.GetTypeInfo().GetDeclaredMethod(configureMethod2);
}
if (methodInfo == null)
{
throw new Exception(string.Format("TODO: {0} or {1} method not found",
configureMethod1,
configureMethod2));
} }
if (methodInfo.ReturnType != typeof(void)) if (methodInfo.ReturnType != typeof(void))
{ {
throw new Exception("TODO: Configuration method isn't void-returning."); throw new Exception(string.Format("TODO: {0} method isn't void-returning.",
methodInfo.Name));
} }
object instance = null; object instance = null;
@ -93,7 +112,35 @@ namespace Microsoft.AspNet.Hosting.Startup
{ {
instance = ActivatorUtilities.GetServiceOrCreateInstance(_services, type); instance = ActivatorUtilities.GetServiceOrCreateInstance(_services, type);
} }
return builder => methodInfo.Invoke(instance, new object[] { builder });
return builder =>
{
var parameterInfos = methodInfo.GetParameters();
var parameters = new object[parameterInfos.Length];
for (var index = 0; index != parameterInfos.Length; ++index)
{
var parameterInfo = parameterInfos[index];
if (parameterInfo.ParameterType == typeof(IBuilder))
{
parameters[index] = builder;
}
else
{
try
{
parameters[index] = _services.GetService(parameterInfo.ParameterType);
}
catch (Exception ex)
{
throw new Exception(string.Format(
"TODO: Unable to resolve service for startup method {0} {1}",
parameterInfo.Name,
parameterInfo.ParameterType.FullName));
}
}
}
methodInfo.Invoke(instance, parameters);
};
} }
} }
} }

View File

@ -32,7 +32,9 @@ namespace Microsoft.AspNet.Hosting.Startup
_providers = providers; _providers = providers;
} }
public Action<IBuilder> LoadStartup(string applicationName) public Action<IBuilder> LoadStartup(
string applicationName,
string environmentName)
{ {
// build ordered chain of application loaders // build ordered chain of application loaders
var chain = _providers var chain = _providers
@ -41,7 +43,7 @@ namespace Microsoft.AspNet.Hosting.Startup
// invoke chain to acquire application entrypoint and diagnostic messages // invoke chain to acquire application entrypoint and diagnostic messages
var diagnosticMessages = new List<string>(); var diagnosticMessages = new List<string>();
var application = chain.LoadStartup(applicationName, diagnosticMessages); var application = chain.LoadStartup(applicationName, environmentName, diagnosticMessages);
if (application == null) if (application == null)
{ {