Browse Source

Refactored ServiceCollectionRegistrationExtensions, added TryAdd methods.

pull/81/head
Halil İbrahim Kalkan 10 years ago
parent
commit
8545c361f7
  1. 2
      src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs
  2. 121
      src/Volo.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceCollectionRegistrationExtensions.cs
  3. 52
      src/Volo.DependencyInjection/Volo/DependencyInjection/AutoRegistrationHelper.cs
  4. 55
      test/Volo.DependencyInjection.Tests/Volo/DependencyInjection/AutoRegistrationHelper_Tests.cs

2
src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs

@ -36,7 +36,7 @@ namespace Volo.Abp.Uow
scope scope
); );
} }
catch catch(Exception ex)
{ {
scope.Dispose(); scope.Dispose();
throw; throw;

121
src/Volo.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceCollectionRegistrationExtensions.cs

@ -1,9 +1,9 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.DependencyInjection; using Volo.DependencyInjection;
using Volo.ExtensionMethods;
using Volo.Internal; using Volo.Internal;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
@ -12,83 +12,122 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
//TODO: Check if assembly/type is added before or add TryAdd versions of them? //TODO: Check if assembly/type is added before or add TryAdd versions of them?
//TODO: When to use Add, when to use TryAdd? We may think to add conventional interfaces to indicate and attributes to override them. //TODO: When to use Add, when to use TryAdd? We may think to add conventional interfaces to indicate and attributes to override them.
//TODO: Make this code extensible, so we can add other conventions!
public static IServiceCollection AddAssemblyOf<T>(this IServiceCollection services) public static IServiceCollection AddAssemblyOf<T>(this IServiceCollection services)
{ {
return services.AddAssembly(typeof(T).GetTypeInfo().Assembly); return services.AddAssemblyOf<T>(false);
}
public static IServiceCollection TryAddAssemblyOf<T>(this IServiceCollection services)
{
return services.AddAssemblyOf<T>(true);
} }
public static IServiceCollection AddAssembly(this IServiceCollection services, Assembly assembly) public static IServiceCollection AddAssembly(this IServiceCollection services, Assembly assembly)
{ {
var types = AssemblyHelper.GetAllTypes(assembly).Where(t => return services.AddAssembly(assembly, false);
{ }
var typeInfo = t.GetTypeInfo();
return typeInfo.IsClass && !typeInfo.IsAbstract && !typeInfo.IsGenericType && !typeInfo.IsDefined(typeof(SkipAutoRegistrationAttribute));
});
return services.AddTypes(types.ToArray()); public static IServiceCollection TryAddAssembly(this IServiceCollection services, Assembly assembly)
{
return services.AddAssembly(assembly, true);
} }
public static IServiceCollection AddTypes(this IServiceCollection services, params Type[] types) public static IServiceCollection AddTypes(this IServiceCollection services, params Type[] types)
{
return services.AddTypes(false, types);
}
public static IServiceCollection TryAddTypes(this IServiceCollection services, params Type[] types)
{
return services.AddTypes(true, types);
}
public static IServiceCollection AddType(this IServiceCollection services, Type type)
{
return services.AddType(type, false);
}
public static IServiceCollection TryAddType(this IServiceCollection services, Type type)
{
return services.AddType(type, true);
}
internal static IServiceCollection AddAssemblyOf<T>(this IServiceCollection services, bool tryAdd)
{
return services.AddAssembly(typeof(T).GetTypeInfo().Assembly, tryAdd);
}
internal static IServiceCollection AddAssembly(this IServiceCollection services, Assembly assembly, bool tryAdd)
{
var types = AssemblyHelper
.GetAllTypes(assembly)
.Where(t =>
{
var typeInfo = t.GetTypeInfo();
return typeInfo.IsClass &&
!typeInfo.IsAbstract &&
!typeInfo.IsGenericType &&
!typeInfo.IsDefined(typeof(SkipAutoRegistrationAttribute));
});
return services.AddTypes(tryAdd, types.ToArray());
}
internal static IServiceCollection AddTypes(this IServiceCollection services, bool tryAdd, params Type[] types)
{ {
foreach (var type in types) foreach (var type in types)
{ {
services.AddType(type); services.AddType(type, tryAdd);
} }
return services; return services;
} }
public static IServiceCollection AddType(this IServiceCollection services, Type type) internal static IServiceCollection AddType(this IServiceCollection services, Type type, bool tryAdd)
{ {
//TODO: Make this code extensible, so we can add other conventions! var lifeTime = GetServiceLifeTime(type);
if (lifeTime == null)
foreach (var serviceType in FindServiceTypes(type))
{ {
if (typeof(ITransientDependency).GetTypeInfo().IsAssignableFrom(type)) return services;
{ }
services.AddTransient(serviceType, type);
} foreach (var serviceType in AutoRegistrationHelper.GetExposedServices(type))
{
if (typeof(ISingletonDependency).GetTypeInfo().IsAssignableFrom(type)) var serviceDescriptor = ServiceDescriptor.Describe(serviceType, type, lifeTime.Value);
if (tryAdd)
{ {
services.AddSingleton(serviceType, type); services.Add(serviceDescriptor);
} }
else
if (typeof(IScopedDependency).GetTypeInfo().IsAssignableFrom(type))
{ {
services.AddScoped(serviceType, type); services.TryAdd(serviceDescriptor);
} }
} }
return services; return services;
} }
private static IEnumerable<Type> FindServiceTypes(Type type) [CanBeNull]
internal static ServiceLifetime? GetServiceLifeTime(Type type)
{ {
var customExposedServices = type.GetTypeInfo().GetCustomAttributes().OfType<IExposedServiceTypesProvider>().SelectMany(p => p.GetExposedServiceTypes()).ToList(); if (typeof(ITransientDependency).GetTypeInfo().IsAssignableFrom(type))
if (customExposedServices.Any())
{ {
return customExposedServices; return ServiceLifetime.Transient;
} }
var serviceTypes = new List<Type> { type }; if (typeof(ISingletonDependency).GetTypeInfo().IsAssignableFrom(type))
foreach (var interfaceType in type.GetTypeInfo().GetInterfaces())
{ {
var interfaceName = interfaceType.Name; return ServiceLifetime.Singleton;
if (interfaceName.StartsWith("I")) }
{
interfaceName = interfaceName.Right(interfaceName.Length - 1);
}
if (type.Name.EndsWith(interfaceName)) if (typeof(IScopedDependency).GetTypeInfo().IsAssignableFrom(type))
{ {
serviceTypes.Add(interfaceType); return ServiceLifetime.Scoped;
}
} }
return serviceTypes; return null;
} }
} }
} }

52
src/Volo.DependencyInjection/Volo/DependencyInjection/AutoRegistrationHelper.cs

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Volo.ExtensionMethods;
namespace Volo.DependencyInjection
{
public static class AutoRegistrationHelper
{
public static IEnumerable<Type> GetExposedServices(Type type)
{
var typeInfo = type.GetTypeInfo();
var customExposedServices = typeInfo
.GetCustomAttributes()
.OfType<IExposedServiceTypesProvider>()
.SelectMany(p => p.GetExposedServiceTypes())
.ToList();
if (customExposedServices.Any())
{
return customExposedServices;
}
return GetDefaultExposedServices(type);
}
private static IEnumerable<Type> GetDefaultExposedServices(Type type)
{
var typeInfo = type.GetTypeInfo();
var serviceTypes = new List<Type> { type };
foreach (var interfaceType in typeInfo.GetInterfaces())
{
var interfaceName = interfaceType.Name;
if (interfaceName.StartsWith("I"))
{
interfaceName = interfaceName.Right(interfaceName.Length - 1);
}
if (type.Name.EndsWith(interfaceName))
{
serviceTypes.Add(interfaceType);
}
}
return serviceTypes;
}
}
}

55
test/Volo.DependencyInjection.Tests/Volo/DependencyInjection/AutoRegistrationHelper_Tests.cs

@ -0,0 +1,55 @@
using System.Linq;
using Shouldly;
using Xunit;
namespace Volo.DependencyInjection
{
public class AutoRegistrationHelper_Tests
{
[Fact]
public void Should_Get_Conventional_Exposed_Types_By_Default()
{
//Act
var exposedServices = AutoRegistrationHelper.GetExposedServices(typeof(DefaultDerivedService)).ToList();
//Assert
exposedServices.Count.ShouldBe(3);
exposedServices.ShouldContain(typeof(DefaultDerivedService));
exposedServices.ShouldContain(typeof(IService));
exposedServices.ShouldContain(typeof(IDerivedService));
}
[Fact]
public void Should_Get_Custom_Exposed_Types_If_Available()
{
//Act
var exposedServices = AutoRegistrationHelper.GetExposedServices(typeof(ExplicitDerivedService)).ToList();
//Assert
exposedServices.Count.ShouldBe(1);
exposedServices.ShouldContain(typeof(IDerivedService));
}
public class DefaultDerivedService : IDerivedService
{
}
public interface IService
{
}
public interface IDerivedService : IService
{
}
[ExposeServices(typeof(IDerivedService))]
public class ExplicitDerivedService : IDerivedService
{
}
}
}
Loading…
Cancel
Save