2017-08-25 3 views
1

Scénario:Rebus avec injection simple rupture de changement

  • application API Web en utilisant la bibliothèque de plusieurs satellites
  • .NET Framework 4.6
  • Injector simple
  • Rebus
  • Rebus.AzureServiceBus
  • Rebus .SimpleInjector

Dans mon application, il existe plusieurs bibliothèques satellites dont la plupart ont une interface SimpleInjector IPackage implémentant une classe, c'est-à-dire, pour grouper des enregistrements de conteneurs dans différentes bibliothèques. Ces paquets s'enregistrés au démarrage

container.RegisterPackages(AppDomain.CurrentDomain.GetAssemblies()); 

L'un des paquets contient la configuration Rebus

IContainerAdapter adapter = new SimpleInjectorContainerAdapter(container); 
Configure.With(adapter) 
      .Transport(t => t.UseAzureServiceBusAsOneWayClient(connectionString, AzureServiceBusMode.Standard)) 
      .Routing(r => 
      r.TypeBased() 
       .MapAssemblyOf<TransactionCreated>("MyQueue") 
      ) 
      .Options(oc => { 
       oc.SetNumberOfWorkers(1); 
      }) 
      .Start(); 

Ce matin, nous avons mis à jour les paquets Rebus aux versions suivantes:

  • Rebus 4.0.1
  • Rebus.AzureServiceBus 4.0.0
  • Rebus .SimpleInjector 4.0.0

Après la mise à niveau du système a cessé de fonctionner et maintenant nous obtenons l'erreur suivante

Le conteneur ne peut pas être modifié après le premier appel à GetInstance, GetAllInstances et vérifier. S'il vous plaît voir https://simpleinjector.org/locked pour comprendre pourquoi le conteneur est verrouillé. La trace de la pile suivante décrit l'emplacement où le conteneur a été verrouillé

Par le débogage du code, nous pouvons voir qu'un autre paquet s'enregistré après celui qui rébus registre et ainsi la raison de l'erreur. Nous pouvons confirmer qu'aucune modification n'a été effectuée au niveau du code et qu'il fonctionnait correctement comme prévu avec les versions précédentes.

Je peux aussi confirmer que en rétrogradant à ces versions, le problème disparaît

  • Rebus 3.1.5
  • Rebus.AzureServiceBus 3.0.0
  • Rebus.SimpleInjector 3.0.0

Une suggestion?

EDIT: selon @Steven demande J'ajoute la totalité trace de pile

Description: Une exception non gérée est survenue pendant l'exécution de la demande Web en cours.S'il vous plaît examiner la trace de la pile pour plus d'informations sur l'erreur et d'où il est originaire dans le code.

Exception Détails: System.InvalidOperationException: Le conteneur ne peut pas être modifié après le premier appel à GetInstance, GetAllInstances et Verify. S'il vous plaît voir https://simpleinjector.org/locked pour comprendre pourquoi le conteneur est verrouillé. La trace de la pile suivante décrit l'emplacement où le conteneur a été verrouillé

at Rebus.SimpleInjector.SimpleInjectorContainerAdapter.SetBus(IBus bus) 
at Rebus.Config.RebusConfigurer.Start() 
at XXX.YYY.EndpointEvents.Producer.IOC.EndpointEventsProducerModule.RegisterServices(Container container) 
at SimpleInjector.PackageExtensions.RegisterPackages(Container container, IEnumerable assemblies) 
at XXX.YYY.WebAPI.SimpleInjectorWebApiInitializer.InitializeContainer(Container container) 
at XXX.YYY.WebAPI.SimpleInjectorWebApiInitializer.Initialize() 
at XXX.YYY.WebAPI.Startup.Configuration(IAppBuilder app) 
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) 
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) 
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
at Owin.Loader.DefaultLoader.<>c__DisplayClass12.<MakeDelegate>b__b(IAppBuilder builder) 
at Owin.Loader.DefaultLoader.<>c__DisplayClass1<LoadImplementation>b__0(IAppBuilder builder) 
at Microsoft.Owin.Host.SystemWeb.OwinHttpModule.<>c__DisplayClass2.<InitializeBlueprint>b__0(IAppBuilder builder) 
at Microsoft.Owin.Host.SystemWeb.OwinAppContext.Initialize(Action startup) 
at Microsoft.Owin.Host.SystemWeb.OwinBuilder.Build(Action startup) 
at Microsoft.Owin.Host.SystemWeb.OwinHttpModule.InitializeBlueprint() 
at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func valueFactory) 
at Microsoft.Owin.Host.SystemWeb.OwinHttpModule.Init(HttpApplication context) 
at System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) 
at System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) 
at System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) 
at System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) 
+0

Bien sûr! S'il vous plaît jeter un oeil à mon édition. – Lorenzo

Répondre

3

Désolé pour être à la fin de réagir à cette question :)

j'avais enfin le temps de comprendre comment SimpleInjector veut l'enregistrement des conteneurs à effectuer, et de comprendre comment l'API de configuration Rebus pourrait en quelque sorte être plié dans le travail de cette façon.

Il est avéré que l'habituel

Configure.With(new MyFavoriteContainerAdapter(container)) 
    .(...) 
    .Start(); 

sort a dû être déplacé en quelque sorte dans un Func<IBus>, permettant de terminer tous les enregistrements Rebus pertinents (ainsi que votre propre) avant de commencer réellement le bus.

Le résultat (qui est dans Rebus.SimpleInjector 5.0.0-b01 sur NuGet.org maintenant) est cette API:

public class RebusPackage : IPackage 
{ 
    public void RegisterServices(Container container) 
    { 
     Console.WriteLine("Calling RebusPackage"); 

     container.ConfigureRebus(
      configurer => configurer 
       .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "test")) 
       .Start() 
     ); 

    } 
} 

qui est la façon dont il peut regarder si vous utilisez SimpleInjector.Packaging , ou tout simplement

container.ConfigureRebus(
    configurer => configurer 
     .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "test")) 
     .Start() 
); 

si tout ce que vous avez est un SimpleInjector container.

Quand vous pensez qu'il est temps de commencer le bus, soit vous

container.StartBus(); 

ou vous attendez IBus est résolu.

+1

Bonjour @ mookid8000, merci pour votre explication. Il semble que tout fonctionne à nouveau bien. Je ferai plus de tests sur cette nouvelle implémentation et je vous ferai savoir si j'obtiendrai des résultats à ce sujet. Merci beaucoup! – Lorenzo

+0

bon à entendre! :) – mookid8000

+1

Excellent travail! Fermeture. Merci encore! – Lorenzo

0

Votre EndpointEventsProducerModule appelle RebusConfigurer.Start. Start résout IBus à partir du conteneur.

Comme les modules peuvent être appelés dans n'importe quel ordre, vous ne devez effectuer des enregistrements que dans des modules. Supprimez l'appel Start et appelez-le après votre appel à container.Verify().

+0

Il Merci pour votre réponse Steven. Le contenu de ce module est exactement au début de la question que j'ai écrite. C'est le même code qui fonctionne avec les versions précédentes des paquets. – Lorenzo

+0

Je ne sais pas à ce sujet. Vous devrez demander aux développeurs Rebus à ce sujet. – Steven

2

Comme vous pouvez le voir here il y a un nouveau codé ajouté pour assurer le bus est disposé, qui a introduit un problème, votre code semble être bien, juste besoin d'attendre le correctif. Ci-dessous les nouvelles lignes

+   // cheat and activate the IBus singleton behind the scenes, thus ensuring that the container will dispose it when it is time 
+   var registration = _container.GetRegistration(typeof(IBus)); 
+ +   registration.GetInstance(); 
+