Added IConventionalRegistrar to add other conventions for registration.

pull/81/head
Halil İbrahim Kalkan 9 years ago
parent aa52be621f
commit 7d79560aee

@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Builder
{
Check.NotNull(app, nameof(app));
app.ApplicationServices.GetRequiredService<ObjectAccessor<IApplicationBuilder>>().Object = app;
app.ApplicationServices.GetRequiredService<ObjectAccessor<IApplicationBuilder>>().Value = app;
app.ApplicationServices.GetRequiredService<AbpApplication>().Initialize(app.ApplicationServices);
}
}

@ -2,7 +2,6 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Volo.Abp.Modularity;
using Volo.DependencyInjection;
namespace Volo.Abp.AspNetCore.Modularity
@ -11,7 +10,7 @@ namespace Volo.Abp.AspNetCore.Modularity
{
public static IApplicationBuilder GetApplicationBuilder(this ApplicationInitializationContext context)
{
return context.ServiceProvider.GetRequiredService<IObjectAccessor<IApplicationBuilder>>().Object;
return context.ServiceProvider.GetRequiredService<IObjectAccessor<IApplicationBuilder>>().Value;
}
public static IHostingEnvironment GetEnvironment(this ApplicationInitializationContext context)

@ -0,0 +1,46 @@
using System.Collections.Generic;
using Volo.DependencyInjection;
using Volo.ExtensionMethods.Collections.Generic;
namespace Microsoft.Extensions.DependencyInjection
{
/* TODO: String IConventionalRegistrar objects in a static Dictionary
* may cause a performance problem if we create too many short lived IServiceCollection instances.
* Normally, an application will have a single IServiceCollection instance, but we should consider edge cases is there are.
*/
public static class ServiceCollectionConventionalRegistrationExtensions
{
private static readonly Dictionary<IServiceCollection, List<IConventionalRegistrar>> ConventionalRegistrars;
static ServiceCollectionConventionalRegistrationExtensions()
{
ConventionalRegistrars = new Dictionary<IServiceCollection, List<IConventionalRegistrar>>();
}
public static IServiceCollection AddConventionalRegistrar(this IServiceCollection services, IConventionalRegistrar registrar)
{
GetOrCreateRegistrarList(services).Add(registrar);
return services;
}
internal static List<IConventionalRegistrar> GetConventionalRegistrars(this IServiceCollection services)
{
return GetOrCreateRegistrarList(services);
}
private static List<IConventionalRegistrar> GetOrCreateRegistrarList(IServiceCollection services)
{
var registrars = ConventionalRegistrars.GetOrDefault(services);
if (registrars == null)
{
registrars = ConventionalRegistrars[services] = new List<IConventionalRegistrar>
{
new DefaultConventionalRegistrar()
};
}
return registrars;
}
}
}

@ -1,17 +1,11 @@
using System;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.DependencyInjection;
using Volo.Internal;
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionRegistrationExtensions
{
//TODO: Make this code extensible, so we can add other conventions! Also, extract default convention to a class which implements the convention interface.
public static IServiceCollection AddAssemblyOf<T>(this IServiceCollection services)
{
return services.AddAssembly(typeof(T).GetTypeInfo().Assembly);
@ -19,82 +13,32 @@ namespace Microsoft.Extensions.DependencyInjection
public static IServiceCollection AddAssembly(this IServiceCollection services, Assembly assembly)
{
var types = AssemblyHelper
.GetAllTypes(assembly)
.Where(t =>
{
var typeInfo = t.GetTypeInfo();
return typeInfo.IsClass &&
!typeInfo.IsAbstract &&
!typeInfo.IsGenericType;
});
return services.AddTypes(types.ToArray());
}
public static IServiceCollection AddTypes(this IServiceCollection services, params Type[] types)
{
foreach (var type in types)
foreach (var registrar in services.GetConventionalRegistrars())
{
services.AddType(type);
registrar.AddAssembly(services, assembly);
}
return services;
}
public static IServiceCollection AddType(this IServiceCollection services, Type type)
public static IServiceCollection AddTypes(this IServiceCollection services, params Type[] types)
{
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsDefined(typeof(DisableConventionalRegistrationAttribute), true))
{
return services;
}
var dependencyAttribute = typeInfo.GetCustomAttributes<DependencyAttribute>(true).FirstOrDefault(); //TODO: Use GetCustomAttribute instead?
var lifeTime = dependencyAttribute?.Lifetime ?? GetServiceLifetimeFromInterfaces(type);
if (lifeTime == null)
foreach (var registrar in services.GetConventionalRegistrars())
{
return services;
}
foreach (var serviceType in AutoRegistrationHelper.GetExposedServices(type))
{
var serviceDescriptor = ServiceDescriptor.Describe(serviceType, type, lifeTime.Value);
if (dependencyAttribute?.TryRegister == true)
{
services.TryAdd(serviceDescriptor);
}
else
{
services.Add(serviceDescriptor);
}
registrar.AddTypes(services, types);
}
return services;
}
[CanBeNull]
internal static ServiceLifetime? GetServiceLifetimeFromInterfaces(Type type)
public static IServiceCollection AddType(this IServiceCollection services, Type type)
{
if (typeof(ITransientDependency).GetTypeInfo().IsAssignableFrom(type))
{
return ServiceLifetime.Transient;
}
if (typeof(ISingletonDependency).GetTypeInfo().IsAssignableFrom(type))
{
return ServiceLifetime.Singleton;
}
if (typeof(IScopedDependency).GetTypeInfo().IsAssignableFrom(type))
foreach (var registrar in services.GetConventionalRegistrars())
{
return ServiceLifetime.Scoped;
registrar.AddType(services, type);
}
return null;
return services;
}
}
}
}

@ -0,0 +1,36 @@
using System;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Volo.Internal;
namespace Volo.DependencyInjection
{
public abstract class ConventionalRegistrarBase : IConventionalRegistrar
{
public virtual void AddAssembly(IServiceCollection services, Assembly assembly)
{
var types = AssemblyHelper
.GetAllTypes(assembly)
.Where(t =>
{
var typeInfo = t.GetTypeInfo();
return typeInfo.IsClass &&
!typeInfo.IsAbstract &&
!typeInfo.IsGenericType;
});
AddTypes(services, types.ToArray());
}
public virtual void AddTypes(IServiceCollection services, params Type[] types)
{
foreach (var type in types)
{
AddType(services, type);
}
}
public abstract void AddType(IServiceCollection services, Type type);
}
}

@ -0,0 +1,63 @@
using System;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Volo.DependencyInjection
{
public class DefaultConventionalRegistrar : ConventionalRegistrarBase
{
public override void AddType(IServiceCollection services, Type type)
{
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsDefined(typeof(DisableConventionalRegistrationAttribute), true))
{
return;
}
var dependencyAttribute = typeInfo.GetCustomAttributes<DependencyAttribute>(true).FirstOrDefault(); //TODO: Use GetCustomAttribute instead?
var lifeTime = dependencyAttribute?.Lifetime ?? GetServiceLifetimeFromInterfaces(type);
if (lifeTime == null)
{
return;
}
foreach (var serviceType in AutoRegistrationHelper.GetExposedServices(type))
{
var serviceDescriptor = ServiceDescriptor.Describe(serviceType, type, lifeTime.Value);
if (dependencyAttribute?.TryRegister == true)
{
services.TryAdd(serviceDescriptor);
}
else
{
services.Add(serviceDescriptor);
}
}
}
protected virtual ServiceLifetime? GetServiceLifetimeFromInterfaces(Type type)
{
if (typeof(ITransientDependency).GetTypeInfo().IsAssignableFrom(type))
{
return ServiceLifetime.Transient;
}
if (typeof(ISingletonDependency).GetTypeInfo().IsAssignableFrom(type))
{
return ServiceLifetime.Singleton;
}
if (typeof(IScopedDependency).GetTypeInfo().IsAssignableFrom(type))
{
return ServiceLifetime.Scoped;
}
return null;
}
}
}

@ -0,0 +1,15 @@
using System;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
namespace Volo.DependencyInjection
{
public interface IConventionalRegistrar
{
void AddAssembly(IServiceCollection services, Assembly assembly);
void AddTypes(IServiceCollection services, params Type[] types);
void AddType(IServiceCollection services, Type type);
}
}

@ -1,7 +1,10 @@
using JetBrains.Annotations;
namespace Volo.DependencyInjection
{
public interface IObjectAccessor<T>
public interface IObjectAccessor<out T>
{
T Object { get; }
[CanBeNull]
T Value { get; }
}
}

@ -1,17 +1,19 @@
using JetBrains.Annotations;
namespace Volo.DependencyInjection
{
public class ObjectAccessor<T> : IObjectAccessor<T>
{
public T Object { get; set; }
public T Value { get; set; }
public ObjectAccessor()
{
}
public ObjectAccessor(T obj)
public ObjectAccessor([CanBeNull] T obj)
{
Object = obj;
Value = obj;
}
}
}

@ -63,16 +63,16 @@ namespace Microsoft.Extensions.DependencyInjection
//Act
var accessor = _services.AddObjectAccessor<MyEmptyClass>();
accessor.Object = obj;
accessor.Value = obj;
//Assert
_services.GetSingletonInstance<IObjectAccessor<MyEmptyClass>>().Object.ShouldBe(obj);
_services.GetSingletonInstance<ObjectAccessor<MyEmptyClass>>().Object.ShouldBe(obj);
_services.GetSingletonInstance<IObjectAccessor<MyEmptyClass>>().Value.ShouldBe(obj);
_services.GetSingletonInstance<ObjectAccessor<MyEmptyClass>>().Value.ShouldBe(obj);
var serviceProvider = _services.BuildServiceProvider();
serviceProvider.GetRequiredService<IObjectAccessor<MyEmptyClass>>().Object.ShouldBe(obj);
serviceProvider.GetRequiredService<ObjectAccessor<MyEmptyClass>>().Object.ShouldBe(obj);
serviceProvider.GetRequiredService<IObjectAccessor<MyEmptyClass>>().Value.ShouldBe(obj);
serviceProvider.GetRequiredService<ObjectAccessor<MyEmptyClass>>().Value.ShouldBe(obj);
}
public class MyTransientClass : ITransientDependency

Loading…
Cancel
Save