Updating DI to use ServiceDescriptors

Fixes #25
This commit is contained in:
Pranav K 2014-03-05 07:22:53 -08:00
parent 1cb8a049f2
commit 914d8e8a3b
9 changed files with 136 additions and 68 deletions

View File

@ -1,30 +1,33 @@
using System; using System;
using System.Reflection;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.ConfigurationModel;
using Microsoft.AspNet.DependencyInjection; using Microsoft.AspNet.DependencyInjection;
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Routing.Owin; using Microsoft.AspNet.Routing.Owin;
using Microsoft.AspNet.Routing.Template; using Microsoft.AspNet.Routing.Template;
using Microsoft.Net.Runtime;
namespace MvcSample.Web namespace MvcSample.Web
{ {
public class Startup public class Startup
{ {
private readonly IApplicationEnvironment _env;
public Startup(IApplicationEnvironment env)
{
_env = env;
}
public void Configuration(IBuilder app) public void Configuration(IBuilder app)
{ {
#if NET45 var configuration = new Configuration();
var appRoot = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; var serviceProvider = new ServiceProvider().Add(MvcServices.GetDefaultServices(configuration, _env));
#else
var appRoot = (string)typeof(AppDomain).GetRuntimeMethod("GetData", new[] { typeof(string) }).Invoke(AppDomain.CurrentDomain, new object[] { "APPBASE" });
#endif
var mvcServices = new MvcServices(appRoot);
var router = app.UseRouter(); var router = app.UseRouter();
var endpoint = ActivatorUtilities.CreateInstance<RouteEndpoint>(mvcServices.Services); var endpoint = ActivatorUtilities.CreateInstance<RouteEndpoint>(serviceProvider);
router.Routes.Add(new TemplateRoute( router.Routes.Add(new TemplateRoute(
endpoint, endpoint,

View File

@ -3,10 +3,12 @@
"dependencies": { "dependencies": {
"Helios" : "0.1-alpha-*", "Helios" : "0.1-alpha-*",
"Microsoft.AspNet.Abstractions": "0.1-alpha-*", "Microsoft.AspNet.Abstractions": "0.1-alpha-*",
"Microsoft.AspNet.ConfigurationModel" : "0.1-alpha-*",
"Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*", "Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*",
"Microsoft.AspNet.Routing" : "0.1-alpha-*", "Microsoft.AspNet.Routing" : "0.1-alpha-*",
"Microsoft.AspNet.Mvc.Core" : "", "Microsoft.AspNet.Mvc.Core" : "",
"Microsoft.AspNet.Mvc" : "" "Microsoft.AspNet.Mvc" : "",
"Microsoft.AspNet.Mvc.Razor" : ""
}, },
"configurations": { "configurations": {
"net45": { }, "net45": { },

View File

@ -1,7 +1,10 @@
using System; using System;
#if NET45
using System.Diagnostics; using System.Diagnostics;
using Microsoft.Net.Runtime;
#if NET45
using Microsoft.Owin.Hosting; using Microsoft.Owin.Hosting;
#endif #endif
namespace MvcSample namespace MvcSample
@ -10,16 +13,19 @@ namespace MvcSample
{ {
const string baseUrl = "http://localhost:9001/"; const string baseUrl = "http://localhost:9001/";
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly IApplicationEnvironment _env;
public Program(IServiceProvider serviceProvider) public Program(IServiceProvider serviceProvider,
IApplicationEnvironment env)
{ {
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_env = env;
} }
public void Main() public void Main()
{ {
#if NET45 #if NET45
using (WebApp.Start(baseUrl, app => new Startup(_serviceProvider).Configuration(app))) using (WebApp.Start(baseUrl, app => new Startup(_serviceProvider, _env).Configuration(app)))
{ {
Console.WriteLine("Listening at {0}", baseUrl); Console.WriteLine("Listening at {0}", baseUrl);
Process.Start(baseUrl); Process.Start(baseUrl);

View File

@ -1,25 +1,28 @@
 #if NET45
#if NET45
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.ConfigurationModel;
using Microsoft.AspNet.DependencyInjection; using Microsoft.AspNet.DependencyInjection;
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Routing.Owin; using Microsoft.AspNet.Routing.Owin;
using Microsoft.AspNet.Routing.Template; using Microsoft.AspNet.Routing.Template;
using Microsoft.Net.Runtime;
using Owin; using Owin;
namespace MvcSample namespace MvcSample
{ {
public class Startup public class Startup
{ {
private IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly IApplicationEnvironment _env;
public Startup(IServiceProvider serviceProvider) public Startup(IServiceProvider serviceProvider,
IApplicationEnvironment env)
{ {
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_env = env;
} }
public void Configuration(IAppBuilder app) public void Configuration(IAppBuilder app)
@ -32,13 +35,13 @@ namespace MvcSample
private void ConfigureMvc(IBuilder builder) private void ConfigureMvc(IBuilder builder)
{ {
string appRoot = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; var configuration = new Configuration();
var services = MvcServices.GetDefaultServices(configuration, _env);
var mvcServices = new MvcServices(appRoot, _serviceProvider); var serviceProvider = new ServiceProvider().Add(services);
var router = builder.UseRouter(); var router = builder.UseRouter();
var endpoint = ActivatorUtilities.CreateInstance<RouteEndpoint>(mvcServices.Services); var endpoint = ActivatorUtilities.CreateInstance<RouteEndpoint>(serviceProvider);
router.Routes.Add(new TemplateRoute( router.Routes.Add(new TemplateRoute(
endpoint, endpoint,
@ -49,7 +52,6 @@ namespace MvcSample
endpoint, endpoint,
"{controller}/{action}", "{controller}/{action}",
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase) { { "controller", "Home" }, { "action", "Index" } })); new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase) { { "controller", "Home" }, { "action", "Index" } }));
} }
} }
} }

View File

@ -2,10 +2,12 @@
"version" : "0.1-alpha-*", "version" : "0.1-alpha-*",
"dependencies": { "dependencies": {
"Microsoft.AspNet.Abstractions": "0.1-alpha-*", "Microsoft.AspNet.Abstractions": "0.1-alpha-*",
"Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*",
"Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*", "Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*",
"Microsoft.AspNet.Routing" : "0.1-alpha-*", "Microsoft.AspNet.Routing" : "0.1-alpha-*",
"Microsoft.AspNet.Mvc.Core" : "", "Microsoft.AspNet.Mvc.Core" : "",
"Microsoft.AspNet.Mvc" : "" "Microsoft.AspNet.Mvc" : "",
"Microsoft.AspNet.Mvc.Razor": ""
}, },
"configurations": { "configurations": {
"net45": { "net45": {

View File

@ -5,6 +5,7 @@ using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp;
using Microsoft.Net.Runtime;
using Microsoft.Net.Runtime.Services; using Microsoft.Net.Runtime.Services;
namespace Microsoft.AspNet.Mvc.Razor.Compilation namespace Microsoft.AspNet.Mvc.Razor.Compilation

View File

@ -1,6 +1,7 @@
using System.Runtime.Versioning; using System.Runtime.Versioning;
using Microsoft.Net.Runtime.Services;
namespace Microsoft.Net.Runtime.Services namespace Microsoft.Net.Runtime
{ {
[AssemblyNeutral] [AssemblyNeutral]
public interface IApplicationEnvironment public interface IApplicationEnvironment

View File

@ -1,79 +1,129 @@
using System; using System;
using System.Collections.Generic;
using Microsoft.AspNet.ConfigurationModel;
using Microsoft.AspNet.DependencyInjection; using Microsoft.AspNet.DependencyInjection;
using Microsoft.AspNet.DependencyInjection.NestedProviders; using Microsoft.AspNet.DependencyInjection.NestedProviders;
using Microsoft.AspNet.FileSystems; using Microsoft.AspNet.FileSystems;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Razor; using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Net.Runtime;
namespace Microsoft.AspNet.Mvc namespace Microsoft.AspNet.Mvc
{ {
public class MvcServices public class MvcServices
{ {
public ServiceProvider Services { get; private set; } public static IEnumerable<IServiceDescriptor> GetDefaultServices(IConfiguration configuration,
IApplicationEnvironment env)
public MvcServices(string appRoot)
: this(appRoot, null)
{ {
} yield return DescribeService<IControllerFactory, DefaultControllerFactory>(configuration);
yield return DescribeService<IControllerDescriptorFactory, DefaultControllerDescriptorFactory>(configuration);
yield return DescribeService<IActionSelector, DefaultActionSelector>(configuration);
yield return DescribeService<IActionInvokerFactory, ActionInvokerFactory>(configuration);
yield return DescribeService<IActionResultHelper, ActionResultHelper>(configuration);
yield return DescribeService<IActionResultFactory, ActionResultFactory>(configuration);
yield return DescribeService<IParameterDescriptorFactory, DefaultParameterDescriptorFactory>(configuration);
yield return DescribeService<IValueProviderFactory, RouteValueValueProviderFactory>(configuration);
yield return DescribeService<IValueProviderFactory, QueryStringValueProviderFactory>(configuration);
yield return DescribeService<IControllerAssemblyProvider, AppDomainControllerAssemblyProvider>(configuration);
yield return DescribeService<IActionDiscoveryConventions, DefaultActionDiscoveryConventions>(configuration);
yield return DescribeService<IFileSystem>(new PhysicalFileSystem(env.ApplicationBasePath));
public MvcServices(string appRoot, IServiceProvider hostServiceProvider) yield return DescribeService<IMvcRazorHost>(new MvcRazorHost(typeof(RazorView).FullName));
{
Services = new ServiceProvider();
Add<IControllerFactory, DefaultControllerFactory>();
Add<IControllerDescriptorFactory, DefaultControllerDescriptorFactory>();
Add<IActionSelector, DefaultActionSelector>();
Add<IActionInvokerFactory, ActionInvokerFactory>();
Add<IActionResultHelper, ActionResultHelper>();
Add<IActionResultFactory, ActionResultFactory>();
Add<IParameterDescriptorFactory, DefaultParameterDescriptorFactory>();
Add<IControllerAssemblyProvider, AppDomainControllerAssemblyProvider>();
Add<IActionDiscoveryConventions, DefaultActionDiscoveryConventions>();
AddInstance<IFileSystem>(new PhysicalFileSystem(appRoot));
AddInstance<IMvcRazorHost>(new MvcRazorHost(typeof(RazorView).FullName));
#if NET45 #if NET45
// TODO: Container chaining to flow services from the host to this container // TODO: Container chaining to flow services from the host to this container
Add<ICompilationService, CscBasedCompilationService>(); yield return DescribeService<ICompilationService, CscBasedCompilationService>(configuration);
// TODO: Make this work like normal when we get container chaining // TODO: Make this work like normal when we get container chaining
// TODO: Update this when we have the new host services // TODO: Update this when we have the new host services
// AddInstance<ICompilationService>(new RoslynCompilationService(hostServiceProvider)); // AddInstance<ICompilationService>(new RoslynCompilationService(hostServiceProvider));
#endif #endif
Add<IRazorCompilationService, RazorCompilationService>(); yield return DescribeService<IRazorCompilationService, RazorCompilationService>(configuration);
Add<IVirtualPathViewFactory, VirtualPathViewFactory>(); yield return DescribeService<IVirtualPathViewFactory, VirtualPathViewFactory>(configuration);
Add<IViewEngine, RazorViewEngine>(); yield return DescribeService<IViewEngine, RazorViewEngine>(configuration);
Add<IModelMetadataProvider, DataAnnotationsModelMetadataProvider>();
Add<IActionBindingContextProvider, DefaultActionBindingContextProvider>();
// This is temporary until DI has some magic for it // This is temporary until DI has some magic for it
Add<INestedProviderManager<ActionDescriptorProviderContext>, NestedProviderManager<ActionDescriptorProviderContext>>(); yield return DescribeService<INestedProviderManager<ActionDescriptorProviderContext>,
Add<INestedProviderManager<ActionInvokerProviderContext>, NestedProviderManager<ActionInvokerProviderContext>>(); NestedProviderManager<ActionDescriptorProviderContext>>(configuration);
Add<INestedProvider<ActionDescriptorProviderContext>, ReflectedActionDescriptorProvider>(); yield return DescribeService<INestedProviderManager<ActionInvokerProviderContext>,
Add<INestedProvider<ActionInvokerProviderContext>, ActionInvokerProvider>(); NestedProviderManager<ActionInvokerProviderContext>>(configuration);
yield return DescribeService<INestedProvider<ActionDescriptorProviderContext>,
ReflectedActionDescriptorProvider>(configuration);
yield return DescribeService<INestedProvider<ActionInvokerProviderContext>,
ActionInvokerProvider>(configuration);
Add<IValueProviderFactory, RouteValueValueProviderFactory>(); yield return DescribeService<IModelMetadataProvider, DataAnnotationsModelMetadataProvider>(configuration);
Add<IValueProviderFactory, QueryStringValueProviderFactory>(); yield return DescribeService<IActionBindingContextProvider, DefaultActionBindingContextProvider>(configuration);
Add<IModelBinder, TypeConverterModelBinder>(); yield return DescribeService<IValueProviderFactory, RouteValueValueProviderFactory>(configuration);
Add<IModelBinder, TypeMatchModelBinder>(); yield return DescribeService<IValueProviderFactory, QueryStringValueProviderFactory>(configuration);
Add<IModelBinder, GenericModelBinder>();
Add<IModelBinder, MutableObjectModelBinder>();
Add<IModelBinder, ComplexModelDtoModelBinder>();
Add<IInputFormatter, JsonInputFormatter>(); yield return DescribeService<IModelBinder, TypeConverterModelBinder>(configuration);
yield return DescribeService<IModelBinder, TypeMatchModelBinder>(configuration);
yield return DescribeService<IModelBinder, GenericModelBinder>(configuration);
yield return DescribeService<IModelBinder, MutableObjectModelBinder>(configuration);
yield return DescribeService<IModelBinder, ComplexModelDtoModelBinder>(configuration);
yield return DescribeService<IInputFormatter, JsonInputFormatter>(configuration);
} }
private void Add<T, TU>() where TU : T public static IServiceDescriptor DescribeService<TService, TImplementation>(
IConfiguration configuration,
LifecycleKind lifecycle = LifecycleKind.Transient)
{ {
Services.Add<T, TU>(); return DescribeService(typeof(TService), typeof(TImplementation), configuration, lifecycle);
} }
private void AddInstance<T>(object instance) public static IServiceDescriptor DescribeService<TService>(
TService implementation,
LifecycleKind lifecycle = LifecycleKind.Transient)
{ {
Services.AddInstance<T>(instance); return new ServiceTypeDescriptor(typeof(TService), implementation, lifecycle);
}
public static IServiceDescriptor DescribeService(
Type serviceType,
Type implementationType,
IConfiguration configuration,
LifecycleKind lifecycle)
{
var serviceTypeName = serviceType.FullName;
var implementationTypeName = configuration.Get(serviceTypeName);
if (!String.IsNullOrEmpty(implementationTypeName))
{
try
{
implementationType = Type.GetType(implementationTypeName);
}
catch (Exception ex)
{
throw new Exception(string.Format("TODO: unable to locate implementation {0} for service {1}", implementationTypeName, serviceTypeName), ex);
}
}
return new ServiceTypeDescriptor(serviceType, implementationType, lifecycle);
}
public class ServiceTypeDescriptor : IServiceDescriptor
{
public ServiceTypeDescriptor(Type serviceType, Type implementationType, LifecycleKind lifecycle)
{
ServiceType = serviceType;
ImplementationType = implementationType;
Lifecycle = lifecycle;
}
public ServiceTypeDescriptor(Type serviceType, object implementation, LifecycleKind lifecycle)
{
ServiceType = serviceType;
ImplementationInstance = implementation;
Lifecycle = lifecycle;
}
public LifecycleKind Lifecycle { get; private set; }
public Type ServiceType { get; private set; }
public Type ImplementationType { get; private set; }
public object ImplementationInstance { get; private set; }
} }
} }
} }

View File

@ -2,6 +2,7 @@
"version" : "0.1-alpha-*", "version" : "0.1-alpha-*",
"dependencies": { "dependencies": {
"Microsoft.AspNet.Abstractions" : "0.1-alpha-*", "Microsoft.AspNet.Abstractions" : "0.1-alpha-*",
"Microsoft.AspNet.ConfigurationModel" : "0.1-alpha-*",
"Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*", "Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*",
"Microsoft.AspNet.FileSystems" : "0.1-alpha-*", "Microsoft.AspNet.FileSystems" : "0.1-alpha-*",
"Microsoft.AspNet.Razor" : "0.1-alpha-*", "Microsoft.AspNet.Razor" : "0.1-alpha-*",