Autofac等待模块可用
由于无法保证要解决的模块顺序,因此我在实现这一点时遇到了一些问题: 我有一个模块,它注册一个Autofac等待模块可用,autofac,Autofac,由于无法保证要解决的模块顺序,因此我在实现这一点时遇到了一些问题: 我有一个模块,它注册一个ScheduleService这个ScheduleService负责按设定的间隔触发事件等 我可以使用XML配置加载不同的ischedable项。我遇到的问题是,ischedable项要求ischeduleseservice准备就绪,以便它可以注册自己 所以在我的中 当时的想法是,我可以加载尽可能多的不同的ISchedulable项目 这是我目前在这些scheduleitem模块中执行此操作的方式
ScheduleService
这个ScheduleService
负责按设定的间隔触发事件等
我可以使用XML配置加载不同的ischedable
项。我遇到的问题是,ischedable
项要求ischeduleseservice
准备就绪,以便它可以注册自己
所以在我的
中
当时的想法是,我可以加载尽可能多的不同的ISchedulable
项目
这是我目前在这些scheduleitem模块中执行此操作的方式:
protected override void Load(ContainerBuilder生成器)
{
builder.RegisterCallback(注册表=>
{
var scheduleService=new-TypedService(typeof(isscheduleService));
var registrations=registry.RegistrationsFor(scheduleService);
if(registrations!=null&®istrations.Any())
{
IComponentRegistration componentRegistration=registrations.First();
componentRegistration.Activated+=(发送方,参数)=>
{
IsScheduleService scheduleService=args.Instance作为IsScheduleService;
if(scheduleService!=null)
{
OnScheduleServiceAvailable(args.Context,scheduleService);
}
};
}
});
基础荷载(建筑商);
}
这是每个ScheduleItems中的覆盖
受保护的覆盖无效OnScheduleServiceAvailable(IComponentContext上下文,
isScheduleService(调度服务)
{
scheduleService.Add(
新的SqlSyncSchedulable(已启用、间隔、连接字符串、SqlSelect、,
context.Resolve(),
context.Resolve(),
context.Resolve(),
context.Resolve(),
context.Resolve(),
context.Resolve());
}
这是非常间歇的。ISchedule
项目应该自己注册,但问题是计划
服务可能在这些项目之后注册
一定有办法做到这一点?我认为您的问题不在于模块的加载顺序,而在于依赖关系设计
您应该以一种不会临时耦合的方式设计模块和依赖项
许多可能的设计之一涉及让schedule服务需要一个可能的依赖项列表
在本设计中,ISchedule
的职责是定义可调度操作的参数,您使用AutofacAdapter
模式将每个调度包装到一个ISyncSchedulable
操作中,ScheduleService
需要一个列表,以便在初始化时添加它们
举个例子(遵循你的例子,但不是逐字逐句:我试图说明一点,而不是给出一个完整的解决方案):
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用Autofac;
使用NUnit.Framework;
名称空间示例
{
公共接口计划
{
bool已启用{get;}
长间隔{get;}
字符串连接字符串{get;}
字符串SqlSelect{get;}
}
公课时间表:ISchedule
{
公共布尔启用
{
获取{return true;}
}
公共长假
{
获取{return 100000;}
}
公共字符串连接字符串
{
获取{return“localhost;blabla”;}
}
公共字符串SqlSelect
{
获取{return“选择1作为”;}
}
}
//假设SqlSyncSchedulable继承自公共
//ISyncSchedulable接口
公共接口是同步可调度的
{
无效运行计划(ScheduleService ScheduleService);
}
公共类SqlSyncSchedulable:ISyncSchedulable
{
public ISchedule Schedule{get;private set;}
公共其他服务其他服务{get;private set;}
公共SqlSyncSchedulable(ISSchedule时间表,
其他服务其他服务
/*,iLogger服务Logger服务
IPersonService个人服务*/
)
{
时间表=时间表;
其他服务=其他服务;
//从计划中读取间隔和其他数据,
//像往常一样存储服务引用。
}
公共无效运行计划(ScheduleService ScheduleService)
{
抛出新的NotImplementedException();
}
}
公共服务
{
}
公共类调度服务
{
公共ScheduleService(IList可调度项、OtherService OtherService/*、…其他依赖项*/)
{
//没有添加!Autofac为您提供所有可能的
//ISyncSchedulable组件
SyncSchedulables=可调度;
//…其他依赖项
}
公共IList同步可调度文件{get;set;}
//此代码不是正确的实现,也不是计划程序,
//它只是一个占位符
公众假期表()
{
foreach(同步可调度文件中的var调度)
{
//你的行动包括。。。
时间表。运行时间表(本);
}
}
}
公共类TestModule:Module
{
受保护的覆盖无效负载(ContainerBuilder builder)
{
基础荷载(建筑商);
builder.RegisterType().AsSelf();
builder.RegisterType().AsSelf();
//不要担心应该注册哪种类型,
//并注册从中继承的每个类型
using System;
using System.Collections.Generic;
using System.Linq;
using Autofac;
using NUnit.Framework;
namespace Example
{
public interface ISchedule
{
bool Enabled { get; }
long IntervalMs { get; }
string ConnectionString { get; }
string SqlSelect { get; }
}
public class Schedule : ISchedule
{
public bool Enabled
{
get { return true; }
}
public long IntervalMs
{
get { return 100000; }
}
public string ConnectionString
{
get { return "localhost;blabla"; }
}
public string SqlSelect
{
get { return "select 1 as A"; }
}
}
// let's assume SqlSyncSchedulable inherits from a common
// ISyncSchedulable interface
public interface ISyncSchedulable
{
void RunSchedule(ScheduleService scheduleService);
}
public class SqlSyncSchedulable : ISyncSchedulable
{
public ISchedule Schedule { get; private set; }
public OtherService OtherService { get; private set; }
public SqlSyncSchedulable(ISchedule schedule,
OtherService otherService
/*,ILoggerService loggerService
IPersonService personService, */
)
{
Schedule = schedule;
OtherService = otherService;
// read interval and other data from schedule,
// store service references as usual.
}
public void RunSchedule(ScheduleService scheduleService)
{
throw new NotImplementedException();
}
}
public class OtherService
{
}
public class ScheduleService
{
public ScheduleService(IList<ISyncSchedulable> schedulables, OtherService otherService /*, ... other dependencies */)
{
// there is no ADD! Autofac gives you a list of all possible
// ISyncSchedulable components
SyncSchedulables = schedulables;
// ... other dependencies
}
public IList<ISyncSchedulable> SyncSchedulables { get; set; }
// this code is not a proper implementation, nor a scheduler,
// it's just a placeholder
public void RunSchedules()
{
foreach (var schedule in SyncSchedulables)
{
// do your operations, involving ...
schedule.RunSchedule(this);
}
}
}
public class TestModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterType<ScheduleService>().AsSelf();
builder.RegisterType<OtherService>().AsSelf();
// don't worry about which type should be registered,
// and register each type inheriting from ISchedule
// coming from the current assembly
// You can even use a single registration for all the
// possible implementations of ISchedule, using techniques
// explained in http://docs.autofac.org/en/latest/register/scanning.html
builder.RegisterAssemblyTypes(GetType().Assembly)
.Where(t => t.GetInterfaces().Contains(typeof(ISchedule)))
.AsImplementedInterfaces()
.InstancePerDependency();
// This registration is a partial, because
// SqlSyncChedulable requires a single parameter
// of type ISchedule
builder.RegisterType<SqlSyncSchedulable>()
.AsImplementedInterfaces();
// for each ISchedule class, we register automatically
// a corresponding ISyncSchedulable, which
builder.RegisterAdapter<ISchedule, ISyncSchedulable>(RegisterISyncSchedulableForEachISchedule)
.InstancePerDependency();
}
private ISyncSchedulable RegisterISyncSchedulableForEachISchedule(IComponentContext context, ISchedule schedule)
{
// the parameter of type ISchedule is the corresponding schedule
var scheduleParam = new TypedParameter(typeof(ISchedule), schedule);
// all the other params are resolved automatically by Autofac.
return context.Resolve<ISyncSchedulable>(scheduleParam);
}
}
[TestFixture]
public class AutofacTest
{
[Test]
public void TestServiceResolution()
{
var builder = new ContainerBuilder();
builder.RegisterModule(new TestModule());
var container = builder.Build();
var service = container.Resolve<ScheduleService>();
Assert.That(service.SyncSchedulables[0].GetType(), Is.EqualTo(typeof(SqlSyncSchedulable)));
}
}
}