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
的职责是定义可调度操作的参数,您使用Autofac
Adapter
模式将每个调度包装到一个
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)));
        }

    }
}