2017-10-13 5 views
0

J'ai 2 systèmes, un pour publier des messages et d'autres pour les consommer. Les deux utilisent Masstransit (avec RabbitMQ) et sont implémentés en utilisant ASP.Net web api 2 et OWIN (et Autofac comme conteneur IoC). Tout fonctionne correctement si mon client n'a pas de dépendances, mais lorsque j'injecte une dépendance dans mon client, la méthode Consume n'est jamais exécutée (aucune erreur ne se produit lors de l'initialisation).Enregistrer un IConsumer <T> avec dépendance dans Masstransit utilisant Autofac

Ceci est le correspondant Editeur Code:

//Startup.cs 
public class Startup 
{ 
    public void Configuration(IAppBuilder app) 
    { 
     HttpConfiguration config = new HttpConfiguration(); 

     IContainer container = null; 
     var builder = new ContainerBuilder(); 

     builder.Register(context => 
     { 
      var busControl = Bus.Factory.CreateUsingRabbitMq(cfg => 
      { 
       IRabbitMqHost rabbitMqHost = cfg.Host(new Uri(ConfigurationManager.AppSettings["RabbitMQHost"]), settings => 
       { 
        settings.Username(ConfigurationManager.AppSettings["RabbitMQUser"]); 
        settings.Password(ConfigurationManager.AppSettings["RabbitMQPassword"]); 
       }); 
      }); 

      return busControl; 
     }) 
     .As<IBusControl>() 
     .As<IBus>() 
     .SingleInstance(); 

     // Register Web API controllers 
     builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); 

     // Resolve dependencies 
     container = builder.Build(); 
     config.DependencyResolver = AutofacWebApiDependencyResolver(container); 

     WebApiConfig.Register(config); 
     SwaggerConfig.Register(config); 
     app.UseCors(CorsOptions.AllowAll); 

     // Register the Autofac middleware FIRST. 
     app.UseAutofacMiddleware(container); 
     app.UseWebApi(config); 

     // Starts MassTransit Service bus, and registers stopping of bus on app dispose 
     var bus = container.Resolve<IBusControl>(); 
     var busHandle = bus.StartAsync(); 
     var properties = new AppProperties(app.Properties); 
     if (properties.OnAppDisposing != CancellationToken.None) 
     { 
      properties.OnAppDisposing.Register(() => busHandle.Result.StopAsync(TimeSpan.FromSeconds(30))); 
     } 
    } 
} 

// Controller 
public IHttpActionResult Post() 
{ 
    _bus.Publish<IFooMessage>(new 
    { 
     Foo = "Foo" 
    }); 

    return Ok(); 
} 

Et c'est le pertinent Code de la consommation:

// Startup.cs 
public class Startup 
{ 
    public void Configuration(IAppBuilder app) 
    { 
     HttpConfiguration config = new HttpConfiguration(); 

     IContainer container = null; 
     var builder = new ContainerBuilder(); 

     builder.RegisterType<FooService>().As<IFooService>().InstancePerRequest(); 
     builder.RegisterModule<BusModule>(); 
     builder.RegisterModule<ConsumersModule>(); 

     // Register Web API controllers 
     builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); 

     // Resolve dependencies 
     container = builder.Build(); 
     config.DependencyResolver = new AutofacWebApiDependencyResolver(container); 

     WebApiConfig.Register(config); 
     SwaggerConfig.Register(config); 
     app.UseCors(CorsOptions.AllowAll); 

     // Register the Autofac middleware FIRST. 
     app.UseAutofacMiddleware(container); 
     app.UseWebApi(config); 

     // Starts MassTransit Service bus, and registers stopping of bus on app dispose 
     var bus = container.Resolve<IBusControl>(); 
     var busHandle = bus.StartAsync(); 
     var properties = new AppProperties(app.Properties); 
     if (properties.OnAppDisposing != CancellationToken.None) 
     { 
      properties.OnAppDisposing.Register(() => busHandle.Result.StopAsync(TimeSpan.FromSeconds(30))); 
     } 
    } 
} 

// BusModule.cs 
public class BusModule : Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
     builder.Register(context => 
     { 
      var busControl = Bus.Factory.CreateUsingRabbitMq(cfg => 
      { 
       IRabbitMqHost rabbitMqHost = cfg.Host(new Uri(ConfigurationManager.AppSettings["RabbitMQHost"]), settings => 
       { 
        settings.Username(ConfigurationManager.AppSettings["RabbitMQUser"]); 
        settings.Password(ConfigurationManager.AppSettings["RabbitMQPassword"]); 
       }); 
       cfg.ReceiveEndpoint(rabbitMqHost, "IP.AgilePoint.queue", ec => 
       { 
        ec.LoadFrom(context); 
       }); 
      }); 

      return busControl; 
     }) 
     .SingleInstance() 
     .As<IBusControl>() 
     .As<IBus>(); 
    } 
} 

// ConsumerModule.cs 
public class ConsumersModule : Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
     builder.RegisterType<FooConsumer>(); 
    } 
} 

// FooConsumer.cs 
public class FooConsumer : IConsumer<IFooMessage> 
{ 
    private IFooService _service; 

    public FooConsumer(IFooService service) 
    { 
     _service = service; 
    } 

    public Task Consume(ConsumeContext<IFooMessage> context) 
    { 
     IFooMessage @event = context.Message; 

     _service.DoStuff(@event.Foo); 

     return Task.FromResult(context.Message); 
    } 
} 

Notez mon FooConsumer a une dépendance (constructeur) sur IFooService. J'ai suivi Masstransit documentation mais je n'arrive pas à faire marcher ça. Qu'est-ce que je fais mal?

versions Framework:

  • Net Framework 4.6.1
  • Autofac:
  • 3.5.2 Masstransit: 3.5.7

Mise à jour:

code peut être trouvé in this Github repository

Répondre

0

Enfin j'ai trouvé ce que je faisais mal. Pour une raison quelconque, je ne pouvais pas voir mes files d'attente dans RabbitMQ Management. Quand je suis en mesure de voir la file d'attente d'erreur, j'ai remarqué de erreur suivant:

RabbitMQ Error

j'enregistrer mon IFooService de cette façon:

builder.RegisterType<FooService>().As<IFooService>().InstancePerRequest(); 

Le InstancePerRequest() était à l'origine de l'erreur. Si j'inscris le service avec builder.RegisterType<FooService>().As<IFooService>() tout fonctionne bien. Je pense que c'est parce que mon instance de bus fonctionne comme singleton (enregistré comme SingleIsntace()). Le fait d'utiliser un projet web api pour héberger mon bus/les consommateurs m'a causé de la confusion.

Quoi qu'il en soit, merci à @Chris Patterson et @Alexey Zimarev pour me pointer dans la bonne direction de la mise en œuvre (en utilisant l'extension MT pour enregistrer les consommateurs).

+1

L'enregistrement par requête est uniquement applicable lorsque Autofac gère la portée de la demande et ceci est effectué dans le plug-in d'intégration WebAPI. MassTransit n'utilise pas cela. L'enregistrement par défaut est * not singleton *, c'est par dépendance. C'est la bonne portée. MassTransit instancie un consommateur pour chaque message. –

3

Je suggère de regarder la documentation spécifique à Autofac, c'est un conteneur entièrement pris en charge via la bibliothèque d'extension.

http://masstransit-project.com/MassTransit/usage/containers/autofac.html

Le paquet: https://www.nuget.org/packages/masstransit.autofac

+0

Je pense que c'est ce que je fais, sauf si je fais une erreur idiote que je ne peux pas voir ... Mon constructeur FooConsumer n'est jamais appelé –

+0

Vous demandez à MT de charger à partir du contexte, mais je ne peux pas voir tout code où vous enregistrez les consommateurs avec Autofac.Comment voulez-vous qu'ils résolvent s'ils ne sont pas enregistrés? –