Error sharing ServiceModel between .net core and .net 4.6

Error	CS0012	The type 'IReturn<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'ServiceStack.Interfaces, Version=5.0.0.0, Culture=neutral, PublicKeyToken=02c12cbda47e6587'.

I get this error in the net core project when I’m attempting to use the MqClient to publish a Message that belongs in a project that targets .net 4.6 and I’m wondering if sharing of messages is possible between .net core and .net 4.6 projects.

All the projects are referencing the same ServiceStack versions.

This sample project shows the compiler error.

This has been addressed a number of times, please see this answer and read the linked answers/docs:

Thanks for that.

Got an issue now that when I publish a Message from a dotnetcore project it gets sent straight to the dead letter queue.

{"__type":"ServiceStack.Messaging.Message`1[[EmailService.ServiceModel.SendEmail, EmailService.ServiceModel]], ServiceStack.Interfaces","Id":"fe3693748ccb481b89c69c8b9bf8bc33","CreatedDate":"2018-07-13T11:36:05.8376045Z","Priority":0,"RetryAttempts":0,"ReplyId":null,"ReplyTo":null,"Options":1,"Error":null,"Tag":null,"Meta":null,"Body":{"__type":"EmailService.ServiceModel.SendEmail, EmailService.ServiceModel","Name":"HelloFromNetCore"}}

However when I use the publish the same message (shared library from a .net 4.7.1 project) from a .net 4.7.1 project it gets processed.

{"__type":"ServiceStack.Messaging.Message`1[[EmailService.ServiceModel.SendEmail, EmailService.ServiceModel]], ServiceStack.Interfaces","Id":"aeeec42a343b46fb91558358779244b7","CreatedDate":"2018-07-13T11:36:02.3535894Z","Priority":0,"RetryAttempts":0,"ReplyId":null,"ReplyTo":null,"Options":1,"Error":null,"Tag":null,"Meta":null,"Body":{"__type":"EmailService.ServiceModel.SendEmail, EmailService.ServiceModel","Name":"HelloFrom471Service"}}

I’m struggling to find any differences between the messages and the servicebus deadletter error message is : MaxDeliveryCountExceeded

How do I investigate this further?

If I use Service Explorer to resubmit the messages that were not getting processed it will work, ONLY if I change the Body Type to String

The MaxDeliveryCountExceeded indicates the message failed to be processed due to an Exception and was sent to the DLQ.

In your RegisterHandler(ExecuteMessage) API there’s an additional callback to be able to register an Exception Handler should get triggered with the Exception that’s thrown, although typically details about the Exception should be in the Error property when in the DLQ unless there’s an Exception with the library.

I’ve tried

   mqServer.RegisterHandler<SendEmail>(m =>
    {
        var response = ExecuteMessage(m);
        return response;
    }, (handler, message, exception) =>
    {
        Console.WriteLine(exception.Message);
    });

and it doesn’t hit the exception call back.

Could it be in the class ServiceBusMqWorker

#if NETSTANDARD2_0
        public async Task HandleMessageAsync(Microsoft.Azure.ServiceBus.Message msg, CancellationToken token)
        {
            var strMessage = msg.GetBodyString();
            IMessage iMessage = (IMessage)JsonSerializer.DeserializeFromString(strMessage, typeof(IMessage));
            if (iMessage != null)
            {
                iMessage.Meta = new Dictionary<string, string>
                {
                    [ServiceBusMqClient.LockTokenMeta] = msg.SystemProperties.LockToken,
                    [ServiceBusMqClient.QueueNameMeta] = queueName
                };
            }

            Type msgType = iMessage.GetType().GetGenericArguments()[0];
            var messageHandlerFactory = mqMessageFactory.handlerMap[msgType];
            var messageHandler = messageHandlerFactory.CreateMessageHandler();

            messageHandler.ProcessMessage(mqClient, iMessage);
        }
#else
        public void HandleMessage(BrokeredMessage msg)
        {
            try
            {
                string strMessage = msg.GetBody<string>();
                IMessage iMessage = (IMessage)JsonSerializer.DeserializeFromString(strMessage, typeof(IMessage));
                if (iMessage != null)
                {
                    iMessage.Meta = new Dictionary<string, string>();
                    iMessage.Meta[ServiceBusMqClient.LockTokenMeta] = msg.LockToken.ToString();
                    iMessage.Meta[ServiceBusMqClient.QueueNameMeta] = queueName;
                }
                Type msgType = iMessage.GetType().GetGenericArguments()[0];
                var messageHandlerFactory = mqMessageFactory.handlerMap[msgType];
                var messageHandler = messageHandlerFactory.CreateMessageHandler();

                messageHandler.ProcessMessage(mqClient, iMessage);
            }
            catch (Exception ex)
            {
                throw;
            }
        }
#endif

where if the message is sent via a project targeting NetStandard2.0 and is received by a project that targets .net Framework it cannot deserialize correctly?

The modified function for the class ServiceBusMqWorker seems to have fixed it… not sure how much use it would be for you to fix the problem for the library.

public void HandleMessage(BrokeredMessage msg)
{
    try
    {
        Stream stream = msg.GetBody<Stream>();
        StreamReader reader = new StreamReader(stream);
        string strMessage = reader.ReadToEnd();
        if (strMessage.StartsWith("@\u0006string", StringComparison.Ordinal))
        {
            strMessage = strMessage.Substring(64, strMessage.Length - 66);
        }

        IMessage iMessage = (IMessage)JsonSerializer.DeserializeFromString(strMessage, typeof(IMessage));
        if (iMessage != null)
        {
            iMessage.Meta = new Dictionary<string, string>();
            iMessage.Meta[ServiceBusMqClient.LockTokenMeta] = msg.LockToken.ToString();
            iMessage.Meta[ServiceBusMqClient.QueueNameMeta] = queueName;
        }
        Type msgType = iMessage.GetType().GetGenericArguments()[0];
        var messageHandlerFactory = mqMessageFactory.handlerMap[msgType];
        var messageHandler = messageHandlerFactory.CreateMessageHandler();

        messageHandler.ProcessMessage(mqClient, iMessage);
    }
    catch (Exception ex)
    {
        throw;
    }
}

ok the @\u0006string delimiter is mentioned in https://stackoverflow.com/a/33563414/85785 which looks like it could be due to using different implementations to send/receive messages.

Did you add this workaround in the NETSTANDARD2_0 impl?

it was already in the NETSTANDARD2_0 it just had to be reworked for the .net Framework

Digging deeper this is a wire incompatibility ServiceBus created between their .NET and .NET Standard clients as reported in this issue:

I’ve updated both clients to use the same method to strip the incompatible artifact in this commit so if you update to the latest v5.1.1 on MyGet you wont need your workaround anymore.

Thanks for updating the lib so quickly!

Just tried the updated version and it is still the same problem when publishing from a .net core project and handling on .net framework.

msg.GetBody<string>();

in HandleMessage routine for the .Net Framework throws the error

"There was an error deserializing the object of type System.String. The input source is not correctly formatted."

ok that’s annoying, I’ve changed it to use GetBody<Stream>() in this commit, this change is available from v5.1.1 on MyGet.

getting this message in the library now when sending from a .net core and receiving from a .net framework

{“Method not found: ‘System.String ServiceStack.StreamExtensions.ReadToEnd(System.IO.Stream)’.”} | System.Exception {System.MissingMethodException}

MissingMethodException are due to dirty dlls can you try clearing your nuget cache again and restoring:

$ nuget locals all -clear

All that’s sorted now thank you.

The same issue appears when I’ve updated to the latest Windows.Azure.Servicebus v5 on nuget. Looks like some breaking changes on their end…