Send Messages from TopicClient to WCF Subscription Service
How to send Message to ServiceBus topic using TopicClient and receive it with WCF as Subscription Service that acts as a Subscription client, without the use of SubscriptionClient classes of Service Bus?
Relevant Facts and Documentaion:
- NetMessagingBinding provides an automatic way of pulling off messages with its integration with WCFs ReceiveContext. However, you can control it manually by enabling ReceiveContext manual control to true.https://msdn.microsoft.com/en-us/library/system.servicemodel.receivecontextenabledattribute.manualcontrol(v=vs.110).aspx
- Controlling manually would set the brokered message receive mode to "PeekLock" and let the user code handle the completion or abandoning of the message.https://msdn.microsoft.com/en-us/library/windowsazure/microsoft.servicebus.messaging.receivemode.aspx
- When using the WCF publish/subscribe service model, when adding the service endpoint you must specify the topic URI as the address, and the subscription URI as the listening URI.https://msdn.microsoft.com/en-us/library/microsoft.servicebus.messaging.netmessagingbinding.aspx
Solution:
Since the sender and receiver are based on two different technologies we have to make sure the encoding on both sides match and a WCF data contract is defined. Please follow the steps below. Also, here's a good blog where Abhishek (from Service Bus product group) talks about different ways of formatting the content for Service Bus Messages - https://abhishekrlal.com/2012/03/30/formatting-the-content-for-service-bus-messages/
- Define the data contract
static class Constants
{
public const string ContractNamespace = "urn:wcsubscriptionservice";
}
[DataContract(Namespace = Constants.ContractNamespace)]
public class TestMessage
{
[DataMember]
public string MsgNumber { get; set; }
[DataMember]
public string MsgContent { get; set; }
}
- Format the brokered message when sending from client.
BrokeredMessage message = new BrokeredMessage(new TestMessage() { MsgNumber = 1, MsgContent = "Test Message" }, new DataContractSerializer(typeof(TestMessage)));
// Send message to the topic
topicClient.Send(message);
- Set the ListenURI in WCF Service:
……………………
private static Uri serviceBusEndpointAddress = new Uri("sb://<namespace>.servicebus.windows.net/<topic>");
private static Uri subscriptionUri = new
Uri("sb://<namespace>.servicebus.windows.net/<topic>/subscriptions/<subscription>");
……………………….
var endpoint = new ServiceEndpoint(contract, binding, new
EndpointAddress(serviceBusEndpointAddress.AbsoluteUri));
endpoint.ListenUri = subscriptionUri;
endpoint.Behaviors.Add(transportBehavior);
endpoint.Name = "ReceiveMessage";
- Manually Control the Receive Context, if you would like the user code to control the incoming message for any further processing purposes.
[ServiceContract(Namespace="urn:wcsubscriptionservice")]
public interface IServiceBusReader
{
[OperationContract(IsOneWay = true, Action = "*"), ReceiveContextEnabled(ManualControl = true)]
void ReceiveMessage(TestMessageContract someMsg);
}
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
public class ServiceBusReader : IServiceBusReader
{
public void ReceiveMessage(TestMessageContract someMsg)
{
TestMessage msg = someMsg.TestMessage;
var incomingProperties = OperationContext.Current.IncomingMessageProperties;
var property = incomingProperties[BrokeredMessageProperty.Name] as BrokeredMessageProperty;
ReceiveContext receiveContext;
if (ReceiveContext.TryGet(incomingProperties, out receiveContext))
{
receiveContext.Complete(TimeSpan.FromSeconds(10.0d));
}
else
{
throw new InvalidOperationException("...");
}
}
}
I've attached the sample code, please feel free to use it. Just make sure, you input the values for service bus namespace, key, topic name and subscription name.
Files: TopicSender.cs, WCFSubscriptionService.cs
Comments
- Anonymous
March 31, 2014
Thanks for this great article! I'm actually trying to do the opposite... I want to use a MessageReciever to get dead-letter messages from a topic subscription that were originally sent to the topic via WCF using the NetMessageBinding.I'm receiving the messages just fine, but am unable to deserialize the body. I think what I'm missing is they type of serializer that is used by the NetMessageBinding. Any idea how to do this?Thanks! - Anonymous
April 02, 2014
Thanks for your feedback.Application using WCF and NetMessagingBinding wraps the message in soap envelope and encodes it.msdn.microsoft.com/.../hh532034.aspxHave you tried something like?receiveMessage.GetBody<T>(new DataContractSerializer(typeof(T)))Please refer to Abhishek's blog for more information on formatting of brokered messages.abhishekrlal.com/.../formatting-the-content-for-service-bus-messages - Anonymous
January 10, 2016
Hey I am tried using your code and service starts running but no messages on subscriber side. I am using this code on Windows Service Bus. Can you please help if I need to do some more configurations