2015-06-02 2 views
5

Поскольку порядок модулей решаются не гарантируется У меня возникли некоторые проблемы, достижение этой цели:Autofac ожидание модуля становится доступным

У меня есть модуль, который регистрирует ScheduleService этого ScheduleService отвечает за инициирующие события в наборе интервалы и т. д.

Я могу загрузить в разных IScheduable элементах, которые я делаю так, используя XML Configuration. Проблема, которая у меня есть, - это элементы IScheduable, которые требуют, чтобы IScheduleService был готов, чтобы он мог зарегистрировать себя.

Так в моем <autofac><modules> у меня есть

<module type="Namespace.ScheduleServiceModule, Namespace" /> 

Тогда идея была я мог загрузить как много различных ISchedulable пунктов

<module type="SomeNamespace.ScheudleItem1, SomeNamespace /> 
<module type="SomeNamespace.ScheudleItem2, SomeNamespace /> 
<module type="SomeNamespace.ScheudleItem3, SomeNamespace /> 
<module type="SomeNamespace.ScheudleItem4, SomeNamespace /> 

Это в настоящее время, как я это делаю в этих scheduleitem модулей:

protected override void Load(ContainerBuilder builder) 
{ 
    builder.RegisterCallback(registry => 
    { 
     var scheduleService = new TypedService(typeof(IScheduleService)); 
     var registrations = registry.RegistrationsFor(scheduleService); 
     if (registrations != null && registrations.Any()) 
     { 
      IComponentRegistration componentRegistration = registrations.First(); 
      componentRegistration.Activated += (sender, args) => 
      { 
       IScheduleService scheduleService = args.Instance as IScheduleService; 
       if (scheduleService != null) 
       { 
        OnScheduleServiceAvailable(args.Context, scheduleService); 
       } 
      }; 
     } 
    }); 
    base.Load(builder); 
} 

Это переопределение в каждом из ScheduleItems

protected override void OnScheduleServiceAvailable(IComponentContext context, 
                IScheduleService scheduleService) 
{ 
    scheduleService.Add(
     new SqlSyncSchedulable(Enabled, IntervalMS, ConnectionString, SqlSelect, 
      context.Resolve<ILoggerService>(), 
      context.Resolve<IPersonService>(), 
      context.Resolve<ILoggingEventService>(), 
      context.Resolve<ITemplateService>(), 
      context.Resolve<ITemplateLoggingEventService>(), 
      context.Resolve<IRuntimeSettingsService>())); 
} 

Который является довольно прерывистым. Элемент ISchedule должен регистрироваться, но проблема заключается в том, что услуга Schedule может быть зарегистрирована после этих элементов.

Должен быть способ достичь этого?

+0

Не могли бы вы отредактировать свой вопрос и поделиться своим исходным кодом 'OnScheduleServiceAvailable'? –

+0

Обновлено с помощью OnScheduleServiceAvailable –

+0

Разве вы не можете использовать зависимости на фабриках ('Func ')? Чтобы зависимость не требовалась, пока она не будет запрошена. См. [Делегатные заводы] (http://docs.autofac.org/en/latest/advanced/delegate-factories.html) – wimh

ответ

0

Я думаю, что ваша проблема не в порядке загрузки модуля, а вместо этого - в дизайне зависимостей.

Вы должны проектировать свои модули и ваши зависимости таким образом, чтобы они не были связаны во времени.

Один из многих возможных проектов предполагает, что для службы расписания требуется список возможных зависимостей.

В этой конструкции responsibilitt из ISchedule в определении параметров в планируемой операции, вы используете Autofac Adapter шаблона, чтобы обернуть каждый график в ISyncSchedulable операций, и ScheduleService требует List<ISyncSchedulable> для того, чтобы добавить их при инициализации ,

В качестве примера (следуя вашему примеру, но не дословно: Я стараюсь больше, чтобы сделать точку, чем дать полное решение):

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))); 
     } 

    } 
} 

Обратите внимание, что порядок разрешения модулей теперь полностью разъединены с разрешением во время выполнения.

Смежные вопросы