2015-06-02 5 views
5

Perché l'ordine dei moduli in via di risoluzione non è garantito che sto avendo qualche problema raggiungimento di questo:Autofac attesa per il modulo per diventare disponibile

ho un modulo che registri un ScheduleService questo ScheduleService è responsabile per gli eventi di trigger a set intervalli ecc.

Sono in grado di caricare diversi IScheduable elementi che lo fanno utilizzando il XML Configuration. Il problema che ho, è che gli articoli IScheduable richiedono che lo IScheduleService sia pronto in modo che possa registrarsi da solo.

Così nel mio <autofac><modules> ho

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

Poi l'idea mi è stato in grado di caricare in altrettante differenti ISchedulable articoli

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

Questo è attualmente come lo faccio in quei moduli 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); 
} 

Questo è l'override in ciascuno di 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>())); 
} 

Che è abbastanza intermittente. L'elemento ISchedule dovrebbe registrarsi ma il problema è che il servizio potrebbe essere registrato dopo tali elementi.

Ci deve essere un modo per raggiungere questo obiettivo?

+0

Potresti modificare la tua domanda e condividere il tuo codice sorgente "OnScheduleServiceAvailable'? –

+0

Aggiornato con OnScheduleServiceAvailable –

+0

Non è possibile utilizzare dipendenze su fabbriche ('Func ')? Che la dipendenza non ha bisogno di essere disponibile fino a quando non viene richiesto. Vedi [Delegate Factories] (http://docs.autofac.org/en/latest/advanced/delegate-factories.html) – wimh

risposta

0

Penso che il tuo problema non sia nell'ordine di caricamento del modulo, ma piuttosto sulla progettazione delle dipendenze.

Si dovrebbero progettare i moduli e le dipendenze in modo che non siano temporaneamente accoppiati.

Uno dei molti possibili progetti prevede che il servizio di pianificazione richieda un elenco di possibili dipendenze.

In questo disegno, il responsibilitt di un ISchedule è nel definire i parametri di un'operazione pianificabile, si utilizza Autofac Adapter modello per avvolgere ogni programma in un'operazione ISyncSchedulable, e il ScheduleService richiede un List<ISyncSchedulable> per aggiungerli all'inizializzazione .

Come esempio (seguendo il vostro esempio, ma non testualmente: sto cercando di più per fare un punto che dare una soluzione completa):

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

    } 
} 

prega di notare che l'ordine di risoluzione del modulo è ora completamente disaccoppiato con la risoluzione runtime.

Problemi correlati