Rashik Hasnat
Rashik Hasnat

Reputation: 327

Cannot access value of an interface type in azure service bus queue with masstransit

I'm sending a message to azure service bus queue with masstransit where the message model interface has another interface within itself. My message schema is like this:

public interface IMyMessage
{
    Guid NormalProp1 { get; set; }

    IVariableProp VariableProp { get; set; }
}

public interface IVariableProp
{

}

Here IvariableProp is an interface because I want to send variable types of data within it. Like:

public class VarietyProp1 : IVariableProp
{
    public Guid VarietyGuid1 { get; set; }
}

public class YetAnotherVarietyProp : IVariableProp
{
    public Guid YetAnotherVarietyGuid { get; set; }
    public bool YetAnotherVarietyBool { get; set; }
}

And at the end my concrete message is:

public class MyConcreteMessage : IMyMessage
{
    public Guid NormalProp1 { get; set; }

    public IVariableProp VariableProp { get; set; }
}

I've sent an instance of my concrete message to azure service bus queue. The concrete message is like below:

    var variety1 = new MyConcreteMessage()
                       {
                           NormalProp1 = Guid.NewGuid(),
                           VariableProp = new VarietyProp1()
                                              {
                                                  VarietyGuid1 = Guid.NewGuid()
                                              }
                       };

This message is being sent to azure service bus without any problem and all the values are sent correctly. (I checked with azure service bus explorer).

Problem is occurring when I try to consume the message with azure function using masstransit. Here In my Iconsumer code, the value of VariableProp is null. My azure function code is given below:

        using (var dependencyScope = Program.AppDependencyResolver.BeginScope())
        {

            var scopedDependencyResolver = dependencyScope.Resolve<IDependencyResolver>();
            IOperationContext operationContext = dependencyScope.Resolve<OperationContext>();
            var serviceTriggerConfiguration = dependencyScope.Resolve<IServiceBusConsumerConfig>();


            var logger = dependencyScope.Resolve<ILogger>();

            logger.Info(() => $"ConsumeEventsFromQueue function is triggered");
            string convertedMessage = Encoding.UTF8.GetString(message.Body, 0, message.Body.Length);
            var retryCount = serviceTriggerConfiguration.RetryCount;
            var interval = serviceTriggerConfiguration.IntervalInMilliSeconds;
            var receiver = Bus.Factory.CreateBrokeredMessageReceiver(
                binder,
                cfg =>
                {
                    cfg.CancellationToken = cancellationToken;
                    cfg.SetLog(traceWriter);
                    cfg.UseRetry(x => x.Interval(retryCount, interval));
                    cfg.Consumer(() => scopedDependencyResolver.Resolve<EventConsumer>());

                });
            await receiver.Handle(message);

and my consumer code is:

public class EventConsumer:IConsumer<IMyMessage>
{
    public async Task Consume(ConsumeContext<IMyMessage> context)
    {
        var message = context.Message;
    }
}

In the consumer code I can't get the value of VariableProp. When I set debug pointer, it shows something like below:

Here message type is GreenPipes.DynamicInternal.Events.IVariableProp

But when i set debug pointer in my function and convert the byte array of body into string, i could see the value of VariableProp.

Value of variableProp is available here

I'm suspecting the value is being lost/encapsulated when the consumer is called via the code:

cfg.Consumer(() => scopedDependencyResolver.Resolve<EventConsumer>());

What i want is to access the value of VariableProp from the consumer. What can I do?

Upvotes: 1

Views: 171

Answers (1)

nizmow
nizmow

Reputation: 589

This is less a MassTransit issue and more a serialisation issue. When you deserialise IMyMessage it will deserialise IVariableProp as an IVariableProp -- that is, an interface with no properties. This is because there's no way to know from the interface definition which concrete type should be hiding behind the IVariableProp.

Here is a decent blog post detailing the problem and a solution: http://appetere.com/post/serializing-interfaces-with-jsonnet.

My personal suggestion would be to avoid doing this. Keep your message contracts as simple and obvious as possible. I'm not even sure the above solution will work with MassTransit. If you want to travel down the path of madness and continue with this approach, I will offer one piece of advice: it's possible to configure the MassTransit JSON serialiser settings with the singleton JsonMessageSerializer.SerializerSettings.

Upvotes: 1

Related Questions