最近,我们停止使用 自动传真,并开始使用 微软 在我们的netcore3.1的web和console应用中的DependencyInjection。我们还是很喜欢他们两个可以完成我们的解耦设计。只是一个简单的决定,使用原生的 微软 包,如果它能用第三方包做同样的事情。下面是我们尝试迁移的代码,重点是我们已经通过注册类型获得了好处,从 扫描组件我们希望保留这种设计,以降低迁移成本。
所需的Services.cs
在DI之前,为了防止注册爆炸(是的,我们确实有100多个接口和服务),我们不对每个服务进行注册,而是使用扫描组件。
public interface IRepository { }
public interface IUserRepository: IRepository { }
public interface ITodoRepository: IRepository { }
// ...
public interface INum100Repository: IRepository { }
public abstract class RepositoryBase: IRepository { }
public class UserRepository: RepositoryBase, IUserRepository { }
public class TodoRepository: RepositoryBase, ITodoRepository { }
// ...
public class Num100Repository: RepositoryBase, INum100Repository { }
服务模块.cs
旧的(迁移自)。传统的Autofac容器构建器
protected override void Load(Autofac.ContainerBuilder builder)
{
base.Load(builder);
var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
assemblies.SelectMany(x => x.GetReferencedAssemblies())
.Where(t => false == assemblies.Any(a =>a.FullName == t.FullName))
.Distinct()
.ToList()
.ForEach(x => assemblies.Add(AppDomain.CurrentDomain.Load(x)));
var scanAssemblies = assemblies.ToArray();
// Core DAL services
builder.RegisterAssemblyTypes(scanAssemblies)
.PublicOnly()
.Where(t => !t.IsInterface)
.As<IRepository>()
.AsImplementedInterfaces()
.InstancePerDependency();
}
服务收集扩展.cs
新(迁移到)。通过Microsoft.Extensions.DependencyInjection实现IServiceCollection服务描述符。
public static IServiceCollection RegisterAssemblyTypes<T>(this IServiceCollection services, ServiceLifetime lifetime, List<Func<TypeInfo, bool>> predicates = null)
{
var scanAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
scanAssemblies.SelectMany(x => x.GetReferencedAssemblies())
.Where(t => false == scanAssemblies.Any(a => a.FullName == t.FullName))
.Distinct()
.ToList()
.ForEach(x => scanAssemblies.Add(AppDomain.CurrentDomain.Load(x)));
var interfaces = scanAssemblies
.SelectMany(o => o.DefinedTypes
.Where(x => x.IsInterface)
.Where(x => x != typeof(T))
.Where(x => typeof(T).IsAssignableFrom(x))
);
foreach (var @interface in interfaces)
{
var types = scanAssemblies
.SelectMany(o => o.DefinedTypes
.Where(x => x.IsClass)
.Where(x => @interface.IsAssignableFrom(x))
);
if (predicates?.Count() > 0)
{
foreach (var predict in predicates)
{
types = types.Where(predict);
}
}
foreach (var type in types)
{
services.TryAdd(new ServiceDescriptor(
@interface,
type,
lifetime)
);
}
}
return services;
}
启动.cs
所以,最后我们只需在 启动.cs 来注册当前程序集的类型。
public void ConfigureServices(IServiceCollection services)
{
// Other DI
// ...
// Our core DAL services DI
services.RegisterAssemblyTypes<IRepository>(ServiceLifetime.Transient);
}
对于这种迁移的东西,我们还有什么需要注意的吗?感谢任何建议或文档。
我的意思是在评论下的问题是。
考虑到你有服务类型和实现类型。
interface IService1 { }
interface IService2 { }
class Service : IService1, IService2
{ }
Autofac注册码。
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<Service>()
.AsImplementedInterfaces()
// When you use lifetime
.SingleInstance();
var autofacContainer = containerBuilder.Build();
微软扩展DI注册码(类似于你得到的)。
var serviceCollection = new ServiceCollection();
serviceCollection.TryAddSingleton<IService1, Service>();
serviceCollection.TryAddSingleton<IService2, Service>();
var serviceProvider = serviceCollection.BuildServiceProvider();
如果你解决服务类型。
// Autofac
var obj1 = autofacContainer.Resolve<IService1>();
var obj2 = autofacContainer.Resolve<IService2>();
// autofacResult = true
var autofacResult = object.ReferenceEquals(obj1, obj2);
// MS DI
var obj3 = serviceProvider.GetRequiredService<IService1>();
var obj4 = serviceProvider.GetRequiredService<IService2>();
// serviceProviderResult = false
var serviceProviderResult = object.ReferenceEquals(obj3, obj4);
这是因为Autofac将提供的类型注册为单人,并将所有服务类型注册为实现,而MS DI将服务实现类型对注册为单人。