2015-06-02 3 views
5

Da die Reihenfolge der Module nicht gelöst ist nicht garantiert Ich bin ein Problem mit diesem zu erreichen:Autofac Warten auf Modul zur Verfügung zu stehen

Ich habe ein Modul, das ein ScheduleService registriert diese ScheduleService für Triggerereignisse in Reihe verantwortlich ist Intervalle etc.

Ich kann in verschiedenen IScheduable Artikel, die ich so mit der XML Configuration. Das Problem, das ich habe, ist die IScheduable Artikel erfordern die IScheduleService bereit zu sein, so dass es sich registrieren kann.

Also in meinem <autofac><modules> Ich habe

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

Dann die Idee war ich ISchedulable Artikel so viele verschiedene laden in konnte

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

Dies ist zur Zeit, wie ich es in diesen scheduleitem Module tun:

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

Dies ist die Überschreibung in jedem der 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>())); 
} 

Das ist ziemlich intermittierend. Der Artikel ISchedule sollte sich selbst registrieren, aber das Problem ist, dass der Dienst Schedule möglicherweise nach diesen Elementen registriert wird.

Es muss einen Weg geben, dies zu erreichen?

+0

Können Sie Ihre Frage bearbeiten und Ihren 'OnScheduleServiceAvailable' Quellcode teilen? –

+0

Aktualisiert mit dem OnScheduleServiceAvailable –

+0

Können Sie stattdessen keine Abhängigkeiten von Factories ('Func ') verwenden? Dass die Abhängigkeit nicht verfügbar sein muss, bis sie angefordert wird. Siehe [Delegate Factories] (http://docs.autofac.org/en/latest/advanced/delegate-factories.html) – wimh

Antwort

0

Ich denke, Ihr Problem ist nicht in der Ladereihenfolge des Moduls, sondern ist stattdessen über Abhängigkeits-Design.

Sie sollten Ihre Module und Ihre Abhängigkeiten so gestalten, dass sie nicht zeitlich gekoppelt sind.

Eines der vielen möglichen Designs beinhaltet, dass der Zeitplanservice eine Liste möglicher Abhängigkeiten erfordert.

In diesem Entwurf, der responsibilitt eines ISchedule ist die Parameter einer planbaren Operation bei der Definition, verwenden Sie Autofac Adapter Muster jeden Zeitplan in einen ISyncSchedulable Betrieb zu wickeln, und die ScheduleService erfordert eine List<ISyncSchedulable>, um sie bei der Initialisierung hinzufügen .

Als Beispiel (nach Ihrem Beispiel, aber nicht wörtlich: Ich bin mehr versuchen, einen Punkt zu machen als eine vollständige Lösung erhalten): Es wird nun

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

    } 
} 

Bitte beachten Sie, dass die Modul Auflösung, um vollständig entkoppelt mit der Laufzeitauflösung.

Verwandte Themen