From 914d8e8a3b07704fbc52feeb3a0efad14be8eeae Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 5 Mar 2014 07:22:53 -0800 Subject: [PATCH] Updating DI to use ServiceDescriptors Fixes #25 --- samples/MvcSample.Web/Startup.cs | 21 +-- samples/MvcSample.Web/project.json | 4 +- samples/MvcSample/Program.cs | 12 +- samples/MvcSample/Startup.cs | 22 +-- samples/MvcSample/project.json | 4 +- .../Compilation/RoslynCompilationService.cs | 1 + .../Services/IApplicationEnvironment.cs | 3 +- src/Microsoft.AspNet.Mvc/MvcServices.cs | 136 ++++++++++++------ src/Microsoft.AspNet.Mvc/project.json | 1 + 9 files changed, 136 insertions(+), 68 deletions(-) diff --git a/samples/MvcSample.Web/Startup.cs b/samples/MvcSample.Web/Startup.cs index e470afad3a..0a3bfc1af9 100644 --- a/samples/MvcSample.Web/Startup.cs +++ b/samples/MvcSample.Web/Startup.cs @@ -1,30 +1,33 @@ using System; -using System.Reflection; using System.Collections.Generic; using Microsoft.AspNet.Abstractions; +using Microsoft.AspNet.ConfigurationModel; using Microsoft.AspNet.DependencyInjection; using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Routing.Owin; using Microsoft.AspNet.Routing.Template; +using Microsoft.Net.Runtime; namespace MvcSample.Web { public class Startup { + private readonly IApplicationEnvironment _env; + + public Startup(IApplicationEnvironment env) + { + _env = env; + } + public void Configuration(IBuilder app) { -#if NET45 - var appRoot = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; -#else - var appRoot = (string)typeof(AppDomain).GetRuntimeMethod("GetData", new[] { typeof(string) }).Invoke(AppDomain.CurrentDomain, new object[] { "APPBASE" }); -#endif - - var mvcServices = new MvcServices(appRoot); + var configuration = new Configuration(); + var serviceProvider = new ServiceProvider().Add(MvcServices.GetDefaultServices(configuration, _env)); var router = app.UseRouter(); - var endpoint = ActivatorUtilities.CreateInstance(mvcServices.Services); + var endpoint = ActivatorUtilities.CreateInstance(serviceProvider); router.Routes.Add(new TemplateRoute( endpoint, diff --git a/samples/MvcSample.Web/project.json b/samples/MvcSample.Web/project.json index 0df5e2cb91..2ba16c2367 100644 --- a/samples/MvcSample.Web/project.json +++ b/samples/MvcSample.Web/project.json @@ -3,10 +3,12 @@ "dependencies": { "Helios" : "0.1-alpha-*", "Microsoft.AspNet.Abstractions": "0.1-alpha-*", + "Microsoft.AspNet.ConfigurationModel" : "0.1-alpha-*", "Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*", "Microsoft.AspNet.Routing" : "0.1-alpha-*", "Microsoft.AspNet.Mvc.Core" : "", - "Microsoft.AspNet.Mvc" : "" + "Microsoft.AspNet.Mvc" : "", + "Microsoft.AspNet.Mvc.Razor" : "" }, "configurations": { "net45": { }, diff --git a/samples/MvcSample/Program.cs b/samples/MvcSample/Program.cs index 0bf9ce011e..18b39ea4be 100644 --- a/samples/MvcSample/Program.cs +++ b/samples/MvcSample/Program.cs @@ -1,7 +1,10 @@ using System; -#if NET45 using System.Diagnostics; +using Microsoft.Net.Runtime; + +#if NET45 using Microsoft.Owin.Hosting; + #endif namespace MvcSample @@ -10,16 +13,19 @@ namespace MvcSample { const string baseUrl = "http://localhost:9001/"; private readonly IServiceProvider _serviceProvider; + private readonly IApplicationEnvironment _env; - public Program(IServiceProvider serviceProvider) + public Program(IServiceProvider serviceProvider, + IApplicationEnvironment env) { _serviceProvider = serviceProvider; + _env = env; } public void Main() { #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); Process.Start(baseUrl); diff --git a/samples/MvcSample/Startup.cs b/samples/MvcSample/Startup.cs index 62eb3077bd..d9fdff2743 100644 --- a/samples/MvcSample/Startup.cs +++ b/samples/MvcSample/Startup.cs @@ -1,25 +1,28 @@ - -#if NET45 +#if NET45 using System; using System.Collections.Generic; -using System.IO; using Microsoft.AspNet.Abstractions; +using Microsoft.AspNet.ConfigurationModel; using Microsoft.AspNet.DependencyInjection; using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Routing.Owin; using Microsoft.AspNet.Routing.Template; +using Microsoft.Net.Runtime; using Owin; namespace MvcSample { 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; + _env = env; } public void Configuration(IAppBuilder app) @@ -32,13 +35,13 @@ namespace MvcSample private void ConfigureMvc(IBuilder builder) { - string appRoot = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; - - var mvcServices = new MvcServices(appRoot, _serviceProvider); + var configuration = new Configuration(); + var services = MvcServices.GetDefaultServices(configuration, _env); + var serviceProvider = new ServiceProvider().Add(services); var router = builder.UseRouter(); - var endpoint = ActivatorUtilities.CreateInstance(mvcServices.Services); + var endpoint = ActivatorUtilities.CreateInstance(serviceProvider); router.Routes.Add(new TemplateRoute( endpoint, @@ -49,7 +52,6 @@ namespace MvcSample endpoint, "{controller}/{action}", new Dictionary(StringComparer.OrdinalIgnoreCase) { { "controller", "Home" }, { "action", "Index" } })); - } } } diff --git a/samples/MvcSample/project.json b/samples/MvcSample/project.json index 87bdf0b5f1..f41f402b77 100644 --- a/samples/MvcSample/project.json +++ b/samples/MvcSample/project.json @@ -2,10 +2,12 @@ "version" : "0.1-alpha-*", "dependencies": { "Microsoft.AspNet.Abstractions": "0.1-alpha-*", + "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*", "Microsoft.AspNet.Routing" : "0.1-alpha-*", "Microsoft.AspNet.Mvc.Core" : "", - "Microsoft.AspNet.Mvc" : "" + "Microsoft.AspNet.Mvc" : "", + "Microsoft.AspNet.Mvc.Razor": "" }, "configurations": { "net45": { diff --git a/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs b/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs index 10d1603d84..203b105168 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.Net.Runtime; using Microsoft.Net.Runtime.Services; namespace Microsoft.AspNet.Mvc.Razor.Compilation diff --git a/src/Microsoft.AspNet.Mvc.Razor/Services/IApplicationEnvironment.cs b/src/Microsoft.AspNet.Mvc.Razor/Services/IApplicationEnvironment.cs index c691d1b039..09a1a39f1e 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Services/IApplicationEnvironment.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Services/IApplicationEnvironment.cs @@ -1,6 +1,7 @@ using System.Runtime.Versioning; +using Microsoft.Net.Runtime.Services; -namespace Microsoft.Net.Runtime.Services +namespace Microsoft.Net.Runtime { [AssemblyNeutral] public interface IApplicationEnvironment diff --git a/src/Microsoft.AspNet.Mvc/MvcServices.cs b/src/Microsoft.AspNet.Mvc/MvcServices.cs index d7767fb661..f0081faaa2 100644 --- a/src/Microsoft.AspNet.Mvc/MvcServices.cs +++ b/src/Microsoft.AspNet.Mvc/MvcServices.cs @@ -1,79 +1,129 @@ using System; +using System.Collections.Generic; +using Microsoft.AspNet.ConfigurationModel; using Microsoft.AspNet.DependencyInjection; using Microsoft.AspNet.DependencyInjection.NestedProviders; using Microsoft.AspNet.FileSystems; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Razor; +using Microsoft.Net.Runtime; namespace Microsoft.AspNet.Mvc { public class MvcServices { - public ServiceProvider Services { get; private set; } - - public MvcServices(string appRoot) - : this(appRoot, null) + public static IEnumerable GetDefaultServices(IConfiguration configuration, + IApplicationEnvironment env) { - } + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(new PhysicalFileSystem(env.ApplicationBasePath)); - public MvcServices(string appRoot, IServiceProvider hostServiceProvider) - { - Services = new ServiceProvider(); - - Add(); - Add(); - Add(); - Add(); - Add(); - Add(); - Add(); - Add(); - Add(); - AddInstance(new PhysicalFileSystem(appRoot)); - AddInstance(new MvcRazorHost(typeof(RazorView).FullName)); + yield return DescribeService(new MvcRazorHost(typeof(RazorView).FullName)); #if NET45 // TODO: Container chaining to flow services from the host to this container - Add(); + yield return DescribeService(configuration); // TODO: Make this work like normal when we get container chaining // TODO: Update this when we have the new host services // AddInstance(new RoslynCompilationService(hostServiceProvider)); #endif - Add(); - Add(); - Add(); - - Add(); - Add(); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); // This is temporary until DI has some magic for it - Add, NestedProviderManager>(); - Add, NestedProviderManager>(); - Add, ReflectedActionDescriptorProvider>(); - Add, ActionInvokerProvider>(); + yield return DescribeService, + NestedProviderManager>(configuration); + yield return DescribeService, + NestedProviderManager>(configuration); + yield return DescribeService, + ReflectedActionDescriptorProvider>(configuration); + yield return DescribeService, + ActionInvokerProvider>(configuration); - Add(); - Add(); + yield return DescribeService(configuration); + yield return DescribeService(configuration); - Add(); - Add(); - Add(); - Add(); - Add(); + yield return DescribeService(configuration); + yield return DescribeService(configuration); - Add(); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + yield return DescribeService(configuration); + + yield return DescribeService(configuration); } - private void Add() where TU : T + public static IServiceDescriptor DescribeService( + IConfiguration configuration, + LifecycleKind lifecycle = LifecycleKind.Transient) { - Services.Add(); + return DescribeService(typeof(TService), typeof(TImplementation), configuration, lifecycle); } - private void AddInstance(object instance) + public static IServiceDescriptor DescribeService( + TService implementation, + LifecycleKind lifecycle = LifecycleKind.Transient) { - Services.AddInstance(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; } } } } diff --git a/src/Microsoft.AspNet.Mvc/project.json b/src/Microsoft.AspNet.Mvc/project.json index 9cbc3947d7..e9c27917c4 100644 --- a/src/Microsoft.AspNet.Mvc/project.json +++ b/src/Microsoft.AspNet.Mvc/project.json @@ -2,6 +2,7 @@ "version" : "0.1-alpha-*", "dependencies": { "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", + "Microsoft.AspNet.ConfigurationModel" : "0.1-alpha-*", "Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*", "Microsoft.AspNet.FileSystems" : "0.1-alpha-*", "Microsoft.AspNet.Razor" : "0.1-alpha-*",