2013-08-19 2 views
2

У меня возникают проблемы с публикацией общих сообщений для производных типов и с вызовом обработчика с использованием MassTransit v2.8.0.Производные типы не публикуются среди потребителей в MassTransit

Если я публикую сообщение типа HtmlBlockNewMessage, потребитель никогда не вызывается. Если я опубликую объект ServiceBusMessage и измените его на Consumes<ServiceBusMessage>.Context, пользователь вызывается.

Код не подходит для производного типа. Он работает только для родительского типа (ServiceBusMessage).

Типы:

[Serializable] 
public class ServiceBusMessage 
{ 
} 

[Serializable] 
public class ServiceBusResponse 
{ 
    public int ResultCode { get; set; } 
} 

// Request 
[Serializable] 
public class ContentItemMessage : ServiceBusMessage 
{ 
    public string SiteId { get; set; } 
    public string PageId { get; set; } 
    public string ContentItemId { get; set; } 
} 

[Serializable] 
public class HtmlBlockNewMessage : ContentItemMessage 
{ 
    public string HtmlData { get; set; } 
} 

// Response 
[Serializable] 
public class ContentItemMessageResponse : ServiceBusResponse 
{ 
    public string Name { get; set; } 
    public string ItemType { get; set; } 
    public string ItemHandler { get; set; }  
} 

[Serializable] 
public class HtmlBlockNewMessageResponse : ContentItemMessageResponse 
{ 
    public string DataId { get; set; } 
} 

Потребитель:

public class HtmlBlockConsumer : Consumes<HtmlBlockNewMessage>.Context 
{ 
    private IHtmlDataService htmlDataService; 
    public static ILogger Logger { get; set; } 

    public HtmlBlockConsumer() 
     : this(null) 
    { 
    } 

    public HtmlBlockConsumer(IHtmlDataService htmlDataService) 
    { 
     Logger = Log4NetLogger.GetLogger(); 

     this.htmlDataService = htmlDataService ?? IoC.Container.Resolve<IHtmlDataService>(); 
    } 

    public void Consume(IConsumeContext<HtmlBlockNewMessage> message) 
    { 
    // Do some stuff 

     message.Respond(new HtmlBlockNewMessageResponse() { ResultCode = 1 }); 
    } 

} регистрация

автобус со стороны издателя: регистрация

 var bus = ServiceBusFactory.New(sbc => 
     { 
      sbc.EnableMessageTracing(); 

      sbc.UseMsmq(); 
      sbc.VerifyMsmqConfiguration(); 
      sbc.UseMulticastSubscriptionClient(); 
      sbc.SetNetwork("Test"); 
      sbc.UseXmlSerializer(); 
      sbc.UseControlBus(); 

      sbc.ReceiveFrom("msmq://localhost/AuctionCMS.Web.Publisher"); 

      MtServiceBus.ValidateBus(sbc); 
     }); 

     IoC.Container.RegisterInstance(bus); 

шины от стороны потребителей:

 var bus = ServiceBusFactory.New(sbc => 
     { 
      sbc.EnableMessageTracing(); 

      sbc.UseMsmq(); 
      sbc.VerifyMsmqConfiguration(); 
      sbc.UseMulticastSubscriptionClient(); 
      sbc.SetNetwork("Test"); 
      sbc.UseXmlSerializer(); 
      sbc.UseControlBus(); 

      sbc.ReceiveFrom("msmq://localhost/AuctionCMS.Consumer"); 

      sbc.Subscribe(subs => 
      { 
       // These are being manually registered due to some issues getting 
       // StructureMap to scan my assemblies 
       subs.Instance(new HtmlBlockConsumer()); 
       subs.Instance(new BrowserConsumer()); 
       subs.Instance(new OfferConsumer()); 
      }); 
     }); 

     IoC.Container.RegisterInstance(bus); 

Моя публиковать расширение:

public static TR Publish<T, TR>(this IServiceBus bus, T message) where T : ServiceBusMessage where TR : ServiceBusResponse 
    { 
     TR response = null; 

     IoC.Container.Resolve<IServiceBus>().PublishRequest(message, callback => 
      { 
       callback.SetTimeout(10.Seconds()); 

       try 
       { 
        callback.Handle<TR>(m => 
         { 
          response = m;/
         }); 
       } 
       catch (Exception ex) 
       { 

        throw; 
       } 
      }); 

     return response; 
    } 

Телефонный код:

// First I create a message specific to the type of action I am performing 

var message = new HtmlBlockNewMessage() { HtmlData = "Hello" }; 

// Then I call a function which accepts a ContentItemMessage and calls Publish 

public void AddContentItem(ContentItemMessage message) 
{ 
    // Do some preprocessing 

    // This call times out 
    var response = this.auctionCmsServices.Bus.Publish<ContentItemMessage, 
      ContentItemMessageResponse>(message); 

    // Do some more processing 

} 

Это исключение

[RequestTimeoutException: Timeout waiting for response, RequestId: 54910000-307f-20cf-c0c2-08d06b31cf6f] 
    MassTransit.RequestResponse.RequestImpl`1.Wait() in d:\BuildAgent-03\work\aa063b4295dfc097\src\MassTransit\RequestResponse\RequestImpl.cs:124 
    MassTransit.RequestResponseExtensions.PublishRequest(IServiceBus bus, TRequest message, Action`1 configureCallback) in d:\BuildAgent-03\work\aa063b4295dfc097\src\MassTransit\RequestResponseExtensions.cs:31 
    AuctionCMS.Framework.ServiceBus.MtServiceBus.Publish(IServiceBus bus, T message) in c:\Users\rick\Documents\Visual Studio 2012\Projects\AuctionCMS\AuctionCMS.Framework\ServiceBus\MtServiceBus.cs:24 
    AuctionCMS.Framework.Entity.Page.AddContentItem(ISite site, String zone, Int32 location, ContentItemMessage message) in c:\Users\rick\Documents\Visual Studio 2012\Projects\AuctionCMS\AuctionCMS.Framework\Entity\Page.cs:48 
    AuctionCMS.Framework.Entity.Site.SetDefaultContent() in c:\Users\rick\Documents\Visual Studio 2012\Projects\AuctionCMS\AuctionCMS.Framework\Entity\Site.cs:117 
    AuctionCMS.Web.Controllers.AdminSitesController.NewSite(SiteNewModel model, HttpPostedFileBase file) in c:\Users\rick\Documents\Visual Studio 2012\Projects\AuctionCMS\AuctionCMS.Web\Controllers\AdminSitesController.cs:69 
    lambda_method(Closure , ControllerBase , Object[]) +179 
    System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +261 
    System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39 
    System.Web.Mvc.Async.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41() +34 
    System.Web.Mvc.Async.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33() +124 
    System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +838059 
    System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +838059 
    System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +838059 
    System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +838059 
    System.Web.Mvc.Async.<>c__DisplayClass37.<BeginInvokeActionMethodWithFilters>b__36(IAsyncResult asyncResult) +15 
    System.Web.Mvc.Async.<>c__DisplayClass2a.<BeginInvokeAction>b__20() +33 
    System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +838644 
    System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +28 
    System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +15 
    System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +65 
    System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +15 
    System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +51 
    System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +42 
    System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +15 
    System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +51 
    System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +606 
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288 

Edit:

Я пошел с общим подходом, чтобы решить эту проблему. Это некрасиво с точки зрения звонящего, но оно работает.

public TR AddContentItem<T, TR>(T message) where T : ContentItemMessage where TR : ContentItemMessageResponse 
    { 
     var response = this.auctionCmsServices.Bus.Publish<T, TR>(message); 

     return response; 
    } 

Вызывающий код теперь выглядит следующим образом:

page.AddContentItem (новый HtmlBlockNewMessage() {HtmlData = "Это какой-то HTML"});

+0

Как вы регистрируете свой 'IServiceBus' в своем контейнере? И список рассылки может быть лучше для этого, чем здесь, но это зависит от вас. https://groups.google.com/d/pendingmsg/masstransit-discuss – Travis

+0

И почему у вас есть метод расширения на 'IServiceBus', который игнорирует параметр и вытаскивает из контейнера? Мне это кажется странным. Я что-то упускаю? – Travis

+0

Я думаю, что у вас проблема с типизацией, описанная здесь: http://stackoverflow.com/questions/7236971/masstransit-message-mis-typing?rq=1 –

ответ

3

Комментарий пользователя Eugene. Что здесь происходит, вы публикуете сообщение типа ContentItemMessage. Потребитель HtmlBlockNewMessage не будет выполнен, так как сообщение опубликовано как ContentItemMessage и ServiceBusMessage. MassTransit message mis-typing - один из многих вещей, на котором это работает.

Ваших вариантов:

  1. Изменения AddContentItem, чтобы использовать общее, возможно, с ограничением
  2. подержанного отражения для вызова Опубликовать информацию правого типа
  3. Restructure как публиковать вещи, так что это не a issue no

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

+0

Я обновил свой вопрос, как я решил проблему с использованием дженериков с ограничениями. Спасибо за помощь. Возможно, вы захотите предоставить расширение, которое будет работать более элегантно. Еще раз спасибо. – rboarman