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.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<RouteEndpoint>(mvcServices.Services);
var endpoint = ActivatorUtilities.CreateInstance<RouteEndpoint>(serviceProvider);
router.Routes.Add(new TemplateRoute(
endpoint,

View File

@ -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": { },

View File

@ -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);

View File

@ -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<RouteEndpoint>(mvcServices.Services);
var endpoint = ActivatorUtilities.CreateInstance<RouteEndpoint>(serviceProvider);
router.Routes.Add(new TemplateRoute(
endpoint,
@ -49,7 +52,6 @@ namespace MvcSample
endpoint,
"{controller}/{action}",
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase) { { "controller", "Home" }, { "action", "Index" } }));
}
}
}

View File

@ -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": {

View File

@ -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

View File

@ -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

View File

@ -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<IServiceDescriptor> GetDefaultServices(IConfiguration configuration,
IApplicationEnvironment env)
{
}
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)
{
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));
yield return DescribeService<IMvcRazorHost>(new MvcRazorHost(typeof(RazorView).FullName));
#if NET45
// 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: Update this when we have the new host services
// AddInstance<ICompilationService>(new RoslynCompilationService(hostServiceProvider));
#endif
Add<IRazorCompilationService, RazorCompilationService>();
Add<IVirtualPathViewFactory, VirtualPathViewFactory>();
Add<IViewEngine, RazorViewEngine>();
Add<IModelMetadataProvider, DataAnnotationsModelMetadataProvider>();
Add<IActionBindingContextProvider, DefaultActionBindingContextProvider>();
yield return DescribeService<IRazorCompilationService, RazorCompilationService>(configuration);
yield return DescribeService<IVirtualPathViewFactory, VirtualPathViewFactory>(configuration);
yield return DescribeService<IViewEngine, RazorViewEngine>(configuration);
// This is temporary until DI has some magic for it
Add<INestedProviderManager<ActionDescriptorProviderContext>, NestedProviderManager<ActionDescriptorProviderContext>>();
Add<INestedProviderManager<ActionInvokerProviderContext>, NestedProviderManager<ActionInvokerProviderContext>>();
Add<INestedProvider<ActionDescriptorProviderContext>, ReflectedActionDescriptorProvider>();
Add<INestedProvider<ActionInvokerProviderContext>, ActionInvokerProvider>();
yield return DescribeService<INestedProviderManager<ActionDescriptorProviderContext>,
NestedProviderManager<ActionDescriptorProviderContext>>(configuration);
yield return DescribeService<INestedProviderManager<ActionInvokerProviderContext>,
NestedProviderManager<ActionInvokerProviderContext>>(configuration);
yield return DescribeService<INestedProvider<ActionDescriptorProviderContext>,
ReflectedActionDescriptorProvider>(configuration);
yield return DescribeService<INestedProvider<ActionInvokerProviderContext>,
ActionInvokerProvider>(configuration);
Add<IValueProviderFactory, RouteValueValueProviderFactory>();
Add<IValueProviderFactory, QueryStringValueProviderFactory>();
yield return DescribeService<IModelMetadataProvider, DataAnnotationsModelMetadataProvider>(configuration);
yield return DescribeService<IActionBindingContextProvider, DefaultActionBindingContextProvider>(configuration);
Add<IModelBinder, TypeConverterModelBinder>();
Add<IModelBinder, TypeMatchModelBinder>();
Add<IModelBinder, GenericModelBinder>();
Add<IModelBinder, MutableObjectModelBinder>();
Add<IModelBinder, ComplexModelDtoModelBinder>();
yield return DescribeService<IValueProviderFactory, RouteValueValueProviderFactory>(configuration);
yield return DescribeService<IValueProviderFactory, QueryStringValueProviderFactory>(configuration);
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-*",
"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-*",