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.Builder;
using Microsoft.AspNet.Http;
using Microsoft.Framework.Runtime;
namespace KWebStartup
{
public class Startup
{
public void Configuration(IBuilder app)
public void Configure(IBuilder app, IApplicationEnvironment env)
{
app.Run(async context =>
{
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.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": {
"net45": {
},

View File

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

View File

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

View File

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

View File

@ -24,6 +24,9 @@ namespace Microsoft.AspNet.Hosting.Startup
{
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
{
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 Action<IBuilder> LoadStartup(string applicationName, IList<string> diagnosticMessages)
public Action<IBuilder> LoadStartup(
string applicationName,
string environmentName,
IList<string> diagnosticMessages)
{
return null;
}

View File

@ -30,42 +30,49 @@ namespace Microsoft.AspNet.Hosting.Startup
private readonly IServiceProvider _services;
private readonly IStartupLoader _next;
public StartupLoader(IServiceProvider services, IStartupLoader next)
public StartupLoader(
IServiceProvider services,
IStartupLoader next)
{
_services = services;
_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))
{
return _next.LoadStartup(applicationName, diagnosticMessages);
return _next.LoadStartup(applicationName, environmentName, diagnosticMessages);
}
var nameParts = Utilities.SplitTypeName(applicationName);
string typeName = nameParts.Item1;
string assemblyName = nameParts.Item2;
var assembly = Assembly.Load(new AssemblyName(assemblyName));
var assembly = Assembly.Load(new AssemblyName(applicationName));
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;
if (string.IsNullOrEmpty(typeName))
{
typeName = "Startup";
}
var startupName1 = "Startup" + environmentName;
var startupName2 = "Startup";
// 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)
{
// 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)
{
type = typeInfo.AsType();
@ -74,18 +81,30 @@ namespace Microsoft.AspNet.Hosting.Startup
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)
{
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))
{
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;
@ -93,7 +112,35 @@ namespace Microsoft.AspNet.Hosting.Startup
{
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;
}
public Action<IBuilder> LoadStartup(string applicationName)
public Action<IBuilder> LoadStartup(
string applicationName,
string environmentName)
{
// build ordered chain of application loaders
var chain = _providers
@ -41,7 +43,7 @@ namespace Microsoft.AspNet.Hosting.Startup
// invoke chain to acquire application entrypoint and diagnostic messages
var diagnosticMessages = new List<string>();
var application = chain.LoadStartup(applicationName, diagnosticMessages);
var application = chain.LoadStartup(applicationName, environmentName, diagnosticMessages);
if (application == null)
{