Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to serialize Azure ServiceBus Message - Error getting value from 'ExpiresAtUtc'

I need to write a test where I manually create a Microsoft.Azure.ServiceBus.Message and serialize it to JSON. Example code:

    var message = new Microsoft.Azure.ServiceBus.Message
    {
        MessageId = "0c8dfad9-6f0f-4d7f-a248-2a48fc899486",
        CorrelationId = "78b507b0-6266-458d-afe6-7882c935e481",
        Body = Encoding.UTF8.GetBytes("Hello world"),
    };

    var json = JsonConvert.SerializeObject(message);

However, I get the following exception when serializing:

    Newtonsoft.Json.JsonSerializationException : 
Error getting value from 'ExpiresAtUtc' on 'Microsoft.Azure.ServiceBus.Message'.
    ---- System.InvalidOperationException : Operation is not valid due to the current state of the object.

Any ideas how I can create a valid Message (that can be later serialized)? ExpiresAtUtc is get only so cannot be directly set. Is there a way to indirectly set it?

like image 221
bytedev Avatar asked Dec 11 '17 14:12

bytedev


1 Answers

ExpiresAtUtc is set by the broker, considered an internal (SystemProperties collection), and is intentionally designed that way. There was a similar question about testing and if you really need this, the only way to achieve it would be using reflection.

var message = new Message();
//message.TimeToLive = TimeSpan.FromSeconds(10);
var systemProperties = new Message.SystemPropertiesCollection();

// systemProperties.EnqueuedTimeUtc = DateTime.UtcNow.AddMinutes(1);
var bindings = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty;
var value = DateTime.UtcNow.AddMinutes(1);
systemProperties.GetType().InvokeMember("EnqueuedTimeUtc", bindings, Type.DefaultBinder, systemProperties, new object[] { value});
// workaround "ThrowIfNotReceived" by setting "SequenceNumber" value
systemProperties.GetType().InvokeMember("SequenceNumber", bindings, Type.DefaultBinder, systemProperties, new object[] { 1 });

// message.systemProperties = systemProperties;
bindings = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty;
message.GetType().InvokeMember("SystemProperties", bindings,Type.DefaultBinder, message, new object[] { systemProperties });

Note that approach is not coming from Azure Service Bus team as they see it a dangerous practice that could end up in your production.

like image 56
Sean Feldman Avatar answered Oct 19 '22 17:10

Sean Feldman