Closed ssbehera-pmap closed 2 years ago
The error
---> System.FormatException: Could not get .NET type named 'abcd.Api.Core.PubSub.Message, core-pubsub'
at Rebus.Serialization.Json.JsonSerializer.GetTypeOrNull(TransportMessage transportMessage)
at Rebus.Serialization.Json.JsonSerializer.GetMessage(TransportMessage transportMessage, Encoding bodyEncoding)
at Rebus.Serialization.Json.JsonSerializer.Deserialize(TransportMessage transportMessage)
(...)
is the message deserializer complaining that it wasn't able to find the type abcd.Api.Core.PubSub.Message, core-pubsub
.
You should check that your program has access to the "core-pubsub" assembly, and that the namespace "abcd.Api.Core.PubSub" does in fact contain a class named "Message".
Could you check that and tell me what you find? 🙂
@mookid8000
The assembly and namespace is different during serialization and deserialization . The solution / project is completely different for serialization and deserialization . Question is why it's looking for that type , how to avoid it.
solution A sends messages to rabbitmq using rebus . solution B subscribing to the specific channel & receives the message , using rebus .
while in subscriber we have similar class , but not exactly the same name space , however in subscriber side message handler we have used dynamic
var subscriber = new BuiltinHandlerActivator();
subscriber.Handle<dynamic>(async msg => { await ProcessIncomingMessage(msg, config); });
var clientProperties = new Dictionary<string, string>() { { "connection_name", config.QueueName } };
var settings = new JsonSerializerSettings { };
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
settings.MissingMemberHandling = MissingMemberHandling.Ignore;
settings.TypeNameHandling = TypeNameHandling.Auto;
settings.TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple; //<-- this should not look for same type .
Configure.With(subscriber)
.Logging(l => l.ColoredConsole())
.Transport(t => t.UseRabbitMq(config.ConnectionString, config.QueueName)
.AddClientProperties(clientProperties))
.Serialization(s => s.UseNewtonsoftJson(settings))
.Start();
await subscriber.Bus.Advanced.Topics.Subscribe(config.Channel);
_subscribers.Add(subscriber);
however this is working fine with rebus 4.2.1
The assembly and namespace is different during serialization and deserialization (...) however this is working fine with rebus 4.2.1
I don't understand why this would have worked with Rebus 4.2.1, or with any version of Rebus ever, actually.
This thing is: When a .NET program receives a message with some JSON json
and the rbs2-msg-type
header set to "abcd.Api.Core.PubSub.Message, core-pubsub" and the next step is to
var messageBodyObject = JsonConvert.Deserialize(json, type);
it will be necessary for Rebus to somehow translate the string "abcd.Api.Core.PubSub.Message, core-pubsub" into type
of type Type
(😅).
When the header points to a specific assembly, namespace and class name, there's really no option besides having that type available to the receiving .NET program (that is, unless Rebus knows beforehand what type to look up from the type name...)
If you do not want to share DLLs between process (which is a totally valid concern), Rebus provides the option of customizing type names (i.e. mapping them to agreed-upon type names), so that senders/receives agree on what to call specific types!
You can do that out of the box by going
Configure.With(new BuiltinHandlerActivator())
.(...)
.Serialization(c => c.UseCustomMessageTypeNames().AddWithCustomName<Message>("message"))
.Start()
to configure the type name "message" for the type Message
. This has to be done both in the sending and the receiving end, using the same agreed-upon type name. They're free to use different class names though, as the message class name will not affect the serialized format.
You can see a working example here: https://github.com/rebus-org/Rebus/blob/master/Rebus.Tests/Examples/ShowHowToAvoidSharingMessageDllsAcrossProcesses.cs
I hope that makes it clearer how serialization works in Rebus and how you can solve your issue 🙂
@mookid8000 we still have the issue with following implementation
The class Message contains the same members in sender and receiver .
.Serialization(s => s.UseCustomMessageTypeNames().AddWithCustomName<Message>("abcd.Api.Core.PubSub.Message").AllowFallbackToDefaultConvention())
.Start();
error :
Rebus.Exceptions.MessageCouldNotBeDispatchedToAnyHandlersException: Message with ID 377f72b7-380f-48e4-aec8-919f0d5395e0 and type abcd.Api.Core.PubSub.Message, core-pubsub could not be dispatched to any handlers (and will not be retried under the default fail-fast settings)
at Rebus.Pipeline.Receive.DispatchIncomingMessageStep.Process(IncomingStepContext context, Func1 next) at Rebus.Sagas.LoadSagaDataStep.Process(IncomingStepContext context, Func
1 next)
at Rebus.Pipeline.Receive.DeserializeIncomingMessageStep.Process(IncomingStepContext context, Func1 next) at Rebus.Pipeline.Receive.HandleRoutingSlipsStep.Process(IncomingStepContext context, Func
1 next)
at Rebus.DataBus.ClaimCheck.HydrateIncomingMessageStep.Process(IncomingStepContext context, Func1 next) at Rebus.Pipeline.Receive.HandleDeferredMessagesStep.Process(IncomingStepContext context, Func
1 next)
at Rebus.Pipeline.Receive.ActivateHandlersStep.Process(IncomingStepContext context, Func1 next) at Rebus.Retry.FailFast.FailFastStep.Process(IncomingStepContext context, Func
1 next)
at Rebus.Retry.Simple.SimpleRetryStrategyStep.DispatchWithTrackerIdentifier(Func`1 next, String identifierToTrackMessageBy, ITransactionContext transactionContext, String messageId, String secondLevelMessageId)
This is another error, which means that the message was properly serialized – so you have now fixed the System.FormatException
you got in the first place. 🙂
The error you are getting now, MessageCouldNotBeDispatchedToAnyHandlersException
, means that the Rebus instance that received the message could not find a handler for the message.
I now see that you're trying to register a handler for dynamic
subscriber.Handle<dynamic>(async msg => { await ProcessIncomingMessage(msg, config); });
which apparently doesn't work (I've never tried it). What you can do though is to register a handler for object
, and then cast the object to dynamic
when passing it on:
subscriber.Handle<object>(async msg => { await ProcessIncomingMessage((dynamic)msg, config); });
@mookid8000 we tried with subscriber.Handle
I just coded this example: https://github.com/rebus-org/Rebus/blob/master/Rebus.Tests/Examples/DispatchMessageAsDynamic.cs
Could you check it out and see if there's anything being done differently when comparing my code to your code?
@mookid8000
recently we upgraded to dotnet 6 Rebus : 7.0.0-rc4 , Rebus.RabbitMq : 7.4.2
getting issue with rebus
---> System.FormatException: Could not get .NET type named 'abcd.Api.Core.PubSub.Message, core-pubsub' at Rebus.Serialization.Json.JsonSerializer.GetTypeOrNull(TransportMessage transportMessage) at Rebus.Serialization.Json.JsonSerializer.GetMessage(TransportMessage transportMessage, Encoding bodyEncoding) at Rebus.Serialization.Json.JsonSerializer.Deserialize(TransportMessage transportMessage) at Rebus.Compression.UnzippingSerializerDecorator.Deserialize(TransportMessage transportMessage) at Rebus.Pipeline.Receive.DeserializeIncomingMessageStep.Process(IncomingStepContext context, Func1 next) at Rebus.DataBus.ClaimCheck.HydrateIncomingMessageStep.Process(IncomingStepContext context, Func1 next) at Rebus.Pipeline.Receive.HandleDeferredMessagesStep.Process(IncomingStepContext context, Func1 next) at Rebus.Retry.FailFast.FailFastStep.Process(IncomingStepContext context, Func1 next) at Rebus.Retry.Simple.SimpleRetryStrategyStep.DispatchWithTrackerIdentifier(Func`1 next, String identifierToTrackMessageBy, ITransactionContext transactionContext, String messageId, String secondLevelMessageId) --- End of inner exception stack trace ---
we have below serialisation settings
var settings = new JsonSerializerSettings { }; settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; settings.MissingMemberHandling = MissingMemberHandling.Ignore; settings.TypeNameHandling = TypeNameHandling.Auto; settings.TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple;