通过REST向Service Bus Queue发送消息并通过TCP接收消息?

时间:2013-03-13 03:03:31

标签: queue servicebus azureservicebus

我有一个Azure Service Bus队列。我想使用REST API将消息发布到队列,但使用IIS托管的WCF服务使用netMessagingBinding来接收消息。

有没有人有链接到证明这一点的资源?或者是否有人能够提供如何使用REST POST将消息推送到队列然后使用netMessagingBinding接收的代码示例?

我相信在阅读之后有可能:

  

您可以使用REST或.NET托管API向服务发送消息或从服务接收消息,在给定方案中使用不同协议混合和匹配客户端。例如,您可以使用一种协议将消息发送到队列,并使用不同的协议使用它。

http://msdn.microsoft.com/en-us/library/windowsazure/hh780717.aspx

我可以使用netMessagingBinding将消息推送到队列,并使用netMessagingBinding接收。我还可以使用REST POST将消息推送到队列,然后使用REST DELETE从队列接收和删除。我只是无法REST POST消息并通过netMessagingBinding接收

1 个答案:

答案 0 :(得分:3)

NetMessagingBinding始终使用BinaryMessageEncodingBindingElement + NetMessagingTransportBindingElement构建通道堆栈。如果ServiceBus队列/订阅中的BrokeredMessages是普通旧的[text] xml,那么BinaryMessageEncoding将不起作用,使用WCF您将使用带有TextMessageEncoder和NetMessagingTransportBindingElement的CustomBinding。

简而言之,您需要将CustomBinding与TextMessageEncodingBindingElement(使用MessageVersion = None)和NetMessagingTransportBindingElement一起使用,确保Action =“*”,并在ServiceBehavior上设置AddressFilterMode = Any。

以下是使用NetMessagingTransportBindingElement读取普通旧XML消息的两种方法:

解决方案#1 在ServiceContract中使用System.ServiceModel.Channels.Message并调用Message.GetBody()

namespace MessagingConsole
{
    static class Constants {
        public const string ContractNamespace = "http://contoso";
    }

    [DataContract(Namespace = Constants.ContractNamespace)]
    class Record
    {
        [DataMember]
        public string Id { get; set; }
    }

    [ServiceContract]
    interface ITestContract
    {
        [OperationContract(IsOneWay = true, Action="*")]
        void UpdateRecord(Message message);
    }

    [ServiceBehavior(
        AddressFilterMode = AddressFilterMode.Any)] // This is another way to avoid “The message with To ” cannot be processed at the receiver…”
    class TestService : ITestContract
    {
        [OperationBehavior]
        public void UpdateRecord(Message message)
        {
            Record r = message.GetBody<Record>();
            Console.WriteLine("UpdateRecord called! " + r.Id);
        }
    }

    class ServiceProgram
    {
        static void Main(string[] args)
        {
            string solution = "sb://SOMENS";
            string owner = "owner";
            string key = "XXXXXX=";
            string topicPath = "Topic2";
            string subscriptionName = "Sub0";
            TokenProvider tokenProvider = TokenProvider.CreateSharedSecretTokenProvider(owner, key);

            MessagingFactory factory = MessagingFactory.Create(solution, tokenProvider);
            TopicClient sender = factory.CreateTopicClient(topicPath);
            SubscriptionClient receiver = factory.CreateSubscriptionClient(topicPath, subscriptionName, ReceiveMode.ReceiveAndDelete);

            string interopPayload = "<Record xmlns='" + Constants.ContractNamespace + "'><Id>4</Id></Record>";
            BrokeredMessage interopMessage = new BrokeredMessage(new MemoryStream(Encoding.UTF8.GetBytes(interopPayload)), true);
            sender.Send(interopMessage);

            CustomBinding binding = new CustomBinding(
                new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.None },
                new NetMessagingTransportBindingElement());
            ServiceHost serviceHost = new ServiceHost(typeof(TestService), new Uri(solution));
            ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(typeof(ITestContract), binding, topicPath + "/Subscriptions/" + subscriptionName);
            endpoint.Behaviors.Add(new TransportClientEndpointBehavior(tokenProvider));
            serviceHost.Open();
            Console.WriteLine("Service is running");
            Console.ReadLine();            
        }
    }
}

解决方案#2 定义MessageContract数据类型以使期望的Soap合约与interop客户端发送的内容匹配:

namespace MessagingConsole
{
    static class Constants
    {
        public const string ContractNamespace = "http://contoso";
    }

    [DataContract(Namespace = Constants.ContractNamespace)]
    class Record
    {
        [DataMember]
        public string Id { get; set; }
    }

    [MessageContract(IsWrapped=false)]
    class RecordMessageContract
    {
        [MessageBodyMember(Namespace = Constants.ContractNamespace)]
        public Record Record { get; set; }
    }

    [ServiceContract]
    interface ITestContract
    {
        [OperationContract(IsOneWay = true, Action="*")]
        void UpdateRecord(RecordMessageContract recordMessageContract);
    }

    class ServiceProgram
    {
        static void Main(string[] args)
        {
            string solution = "sb://SOMENS";
            string owner = "owner";
            string key = "XXXXXXXXXXXXXX=";
            string topicPath = "Topic2";
            string subscriptionName = "Sub0";
            TokenProvider tokenProvider = TokenProvider.CreateSharedSecretTokenProvider(owner, key);

            MessagingFactory factory = MessagingFactory.Create(solution, tokenProvider);
            TopicClient sender = factory.CreateTopicClient(topicPath);
            SubscriptionClient receiver = factory.CreateSubscriptionClient(topicPath, subscriptionName, ReceiveMode.ReceiveAndDelete);

            string interopPayload = "<Record xmlns='" + Constants.ContractNamespace + "'><Id>5</Id></Record>";
            BrokeredMessage interopMessage = new BrokeredMessage(new MemoryStream(Encoding.UTF8.GetBytes(interopPayload)), true);
            sender.Send(interopMessage);

            CustomBinding binding = new CustomBinding(
                new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.None },
                new NetMessagingTransportBindingElement());
            ServiceHost serviceHost = new ServiceHost(typeof(TestService), new Uri(solution));
            ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(typeof(ITestContract), binding, topicPath + "/Subscriptions/" + subscriptionName);
            endpoint.Behaviors.Add(new TransportClientEndpointBehavior(tokenProvider));
            serviceHost.Open();
            Console.WriteLine("Service is running");
            Console.ReadLine();
        }
    }

    [ServiceBehavior(
        AddressFilterMode = AddressFilterMode.Any
        )]
    class TestService : ITestContract
    {
        [OperationBehavior]
        public void UpdateRecord(RecordMessageContract recordMessageContract)
        {
            Record r = recordMessageContract.Record;
            Console.WriteLine("UpdateRecord called! " + r.Id);
        }
    }
}