user2243747
user2243747

Reputation: 2967

Azure function topic output binding - set custom properties

I am trying to use Azure function output bindings to send message to a service bus topic having one subscription

Following piece of code is doing the job but I am not able to set

[Function(nameof(Function1))]
[ServiceBusOutput("test-topic", Connection = "CONN")]
public async Task<OutputData> Run(
    [ServiceBusTrigger("test-queue", Connection = "CONN")]
    ServiceBusReceivedMessage message,
    ServiceBusMessageActions messageActions,
    ICollector<BrokeredMessage> collector
    )
{
    
    //Following return 
    //Is there any way to set custom properties of this message?
    //Along with custom property, I would also like to set messageProperty contentType to application/json

    OutputData outputData = new OutputData
    {
        ID = 123,
        Name = "Test"
    };

    // Complete the message
    await messageActions.CompleteMessageAsync(message);

    return outputData;

    /*As per solution mentioned [here](https://stackoverflow.com/questions/50457428/custom-message-properties-on-azure-queue-topic-message-from-azure-function), I tried to set custom properties but collector is always null.*/
   
    BrokeredMessage brokeredMessage = new();
    brokeredMessage.ContentType = "application/json";
    brokeredMessage.Properties.Add("ID", 123);
    brokeredMessage.Properties.Add("Name", "Test");
    //Injecting  ICollector<BrokeredMessage>  notworking as its always null.
    //collector.Add(brokeredMessage);
}

I can see outputData has reached to its destination but content type is text/plain and I can't add any custom properties. Service Bus Explorer Snap

I am using

Any pointers ?

UPDATE 1 As suggested by @Dasari Kamali I tried using ServiceBusMessage but still observing same behavior

 #region ServiceBusMessage not working
 ServiceBusMessage serviceBusMessage = new ServiceBusMessage();
 serviceBusMessage.ContentType = "application/json";
 serviceBusMessage.ApplicationProperties.Add("ID", 123);
 serviceBusMessage.ApplicationProperties.Add("Name", "Test");
 serviceBusMessage.Body = BinaryData.FromString("Test");
 #endregion
 // Complete the message
 await messageActions.CompleteMessageAsync(message);
 return serviceBusMessage;

Service Bus Explorer snap

Upvotes: 0

Views: 101

Answers (2)

user2243747
user2243747

Reputation: 2967

It looks like using built-in output bindings we can not add ApplicationProperties. I end up using IAzureClientFactory<ServiceBusSender> to create instance of service bus topic client. And subsequently used ServiceBusMessage to send message to service bus topic by setting ApplicationProperties

builder.Services.AddAzureClients(builder =>
{
    builder.AddServiceBusClient(conn);
    builder.AddClient<ServiceBusSender, ServiceBusClientOptions>((_, _, sp) =>
    {
        var sbClient = sp.GetRequiredService<ServiceBusClient>();
        var sender = sbClient.CreateSender("test-topic");
        return sender;
    }).WithName("test-topic");
});
 public Function1(ILogger<Function1> logger, IAzureClientFactory<ServiceBusSender> sbSender)
 {    
     _clientFactory = sbSender;
 }

 [Function(nameof(Function1))]
 public async Task Run(
     [ServiceBusTrigger("test-queue", Connection = "CONN")]
     ServiceBusReceivedMessage message,
     ServiceBusMessageActions messageActions
     )
 {     
     OutputData outputData = new OutputData
     {
         ID = 123,
         Name = "Test"
     };
     #region Working - Use IAzureClientFactory to send message
     var topic = _clientFactory.CreateClient("test-topic");
     var serviceBusMessage = new ServiceBusMessage(JsonConvert.SerializeObject(outputData))
     {
         ContentType = "application/json"
     };
     serviceBusMessage.ApplicationProperties.Add("ID", 123);
     await topic.SendMessageAsync(serviceBusMessage);
     #endregion
     // Complete the message
     await messageActions.CompleteMessageAsync(message);
 }

enter image description here Complete code is available here - azure-sb-topic-output-binding

Upvotes: 0

Dasari Kamali
Dasari Kamali

Reputation: 3649

I tried your code and got the same issue, so I tried using a ServiceBusQueue trigger function instead.

It manually creates a ServiceBusSender from a ServiceBusClient and explicitly sends the message using SendMessageAsync(). It successfully worked for me to send message to a Service Bus Topic and setting the ContentType as application/json and Custom Properties.

using System.Text;
using Azure.Messaging.ServiceBus;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace FunctionApp24
{
    public class Function1
    {
        private readonly ILogger<Function1> _logger;
        private readonly ServiceBusClient _serviceBusClient;

        public Function1(ILogger<Function1> logger, ServiceBusClient serviceBusClient)
        {
            _logger = logger;
            _serviceBusClient = serviceBusClient;
        }

        [Function(nameof(Function1))]
        public async Task Run(
            [ServiceBusTrigger("kamqueue", Connection = "CONN")] ServiceBusReceivedMessage receivedMessage,
            ServiceBusMessageActions messageActions)
        {
            _logger.LogInformation("Received Message ID: {id}", receivedMessage.MessageId);
            _logger.LogInformation("Received Content-Type: {contentType}", receivedMessage.ContentType);
            _logger.LogInformation("Received Body: {body}", Encoding.UTF8.GetString(receivedMessage.Body.ToArray()));

            var outputData = new
            {
                ID = 123,
                Name = "Test"
            };

            string jsonString = JsonConvert.SerializeObject(outputData);
            byte[] jsonBytes = Encoding.UTF8.GetBytes(jsonString);

            var serviceBusMessage = new ServiceBusMessage(jsonBytes)
            {
                ContentType = "application/json", 
                MessageId = Guid.NewGuid().ToString(),
                CorrelationId = receivedMessage.CorrelationId ?? Guid.NewGuid().ToString(),
                ReplyTo = receivedMessage.ReplyTo,
                SessionId = receivedMessage.SessionId,
                PartitionKey = receivedMessage.PartitionKey,
                TimeToLive = TimeSpan.FromMinutes(10)
            };
            serviceBusMessage.ApplicationProperties["ID"] = 123;
            serviceBusMessage.ApplicationProperties["Name"] = "Test";

            _logger.LogInformation("Final Sent Message Content-Type: {contentType}", serviceBusMessage.ContentType);
            var sender = _serviceBusClient.CreateSender("kamtopic");
            await sender.SendMessageAsync(serviceBusMessage);
            await messageActions.CompleteMessageAsync(receivedMessage);
        }
    }
}

Output :

enter image description here

Azure Service Bus Topic :

I successfully set the contentType as application/json and Custom Properties under Message Properties in the Topic.

enter image description here

Upvotes: 0

Related Questions