• Service Bus Brokered Messaging(Queues和Topic/Subscription)


    Service Bus Brokered Messaging(Queues和Topic/Subscription)中提供了对Session的支持。当我们需要接收方对消息集合进行处理时,或者是按照特定的顺序,或者是一个大消息体分拆成多个BrokeredMessage,或者是存在多个接收方的情况下,需要一系列消息完全由同一接收方实例处理,在这些情况下,Session机制为我们提供了很大的便利。这篇文章将以Queue为例子,介绍一下Session的使用以及如何使用Queue与Session实现Request/Response模式。。

    如何使用Session

    需要使用Session,首先在创建Queue的时候需要将QueueDescription的RequiresSession设置为true,然后在发送消息时将同一集合内的消息的SessionId设置成统一值。接收方不再通过QueueClient接收消息,而是通过QueueClient的AcceptMessageSession方法接受一次会话(MessageSession),再使用MessageSession接收这次会话包含的所有消息。

    需要注意的是,如果Queue的RequiresSession设置为true,则接收方必须通过会话接收消息,否则会抛出InvalidOperationException(It is not possible for an entity that requires sessions to create a non-sessionful message receiver)。并且如果使用会话接收了一条消息,则这个会话内所有消息都由当前接收方接收,其他接收方无法接收这部分消息。所以谁先使用会话接收了第一条消息,则会话内所有消息就属于谁。

    发送消息

    创建队列

    复制代码
     1             string queueName = "MyQueue";
     2             NamespaceManager namespaceClient = NamespaceManager.Create();
     3             if (namespaceClient.QueueExists(queueName))
     4             {
     5                 namespaceClient.DeleteQueue(queueName);
     6             }
     7             QueueDescription queueDescription = new QueueDescription(queueName)
     8             {
     9                 RequiresSession = true
    10             };
    11             namespaceClient.CreateQueue(queueDescription);        
    复制代码

    创建客户端并发送消息

    复制代码
     1             MessagingFactory factory = MessagingFactory.Create();
     2             QueueClient queueClient = factory.CreateQueueClient(queueName);
     3 
     4             string sessionId = Guid.NewGuid().ToString();
     5             CreateAndSendOrderMessage(Guid.NewGuid().ToString(), "Beijing", queueClient, sessionId);
     6             CreateAndSendOrderMessage(Guid.NewGuid().ToString(), "Dalian", queueClient, sessionId);
     7             CreateAndSendOrderMessage(Guid.NewGuid().ToString(), "Guangzhou", queueClient, sessionId);
     8 
     9             var message = new BrokeredMessage();
    10             message.Properties.Add("OrderId", Guid.NewGuid().ToString());
    11             message.Properties.Add("OrderRegion", "Beijing");
    12             Console.WriteLine("Sending message of Order Id:{0}, Session Id:{1}.", message.Properties["OrderId"], message.SessionId);
    13 
    14             Console.WriteLine();
    15             Console.WriteLine("Press [Enter] to delete queue and exit.");
    16             Console.ReadLine();
    17             namespaceClient.DeleteQueue(queueName);
    18             factory.Close();
    19             queueClient.Close();
    复制代码
    复制代码
    1         private static void CreateAndSendOrderMessage(string orderId, string orderRegion, QueueClient sender, string sessionId)
    2         {
    3             var message = new BrokeredMessage();
    4             message.SessionId = sessionId;
    5             message.Properties.Add("OrderId", orderId);
    6             message.Properties.Add("OrderRegion", orderRegion);
    7             Console.WriteLine("Sending message of Order Id:{0}, Session Id:{1}.", orderId, sessionId);
    8             sender.Send(message);
    9         }
    复制代码

    使用Session接收消息

    复制代码
     1             string queueName = "MyQueue";
     2             MessagingFactory factory = MessagingFactory.Create();
     3             QueueClient queueClient = factory.CreateQueueClient(queueName, ReceiveMode.PeekLock);
     4             Console.WriteLine("Reading messages from queue...");
     5 
     6             try
     7             {
     8                 MessageSession session = queueClient.AcceptMessageSession(TimeSpan.FromSeconds(1));
     9                 BrokeredMessage message = null;
    10                 int i = 0;
    11                 while ((message = session.Receive(TimeSpan.FromSeconds(1))) != null)
    12                 {
    13                     Console.WriteLine("Receiving message of Order Id:{0}, Session Id:{1}.", message.Properties["OrderId"], message.SessionId);
    14                     message.Complete();
    15                     i++;
    16                 }
    17             }
    18             catch
    19             { 
    20                 
    21             }
    复制代码

    使用Session实现Request/Response模式

    我们知道,Queue的消息传送完全是异步通信,发送方只负责发送消息,接收方只负责接收,当发送方发出消息以后,接收方不需要给发送方响应,同时也不可能提供响应。而面向服务的设计中,大部分需求都是调用服务后返回调用方需要的资源,即Request/Response通信模式。那么,如果需要用Service Bus Queue来实现这种Request/Response模式,该如何做呢?接下来,我们通过一个例子来看看实现过程。

    在这个例子中,包含两个应用程序,SalesApplication与ProductCatalogApplication。其中SalesApplication将产品ID发送给ProductCatalogApplication,ProductCatalogApplication根据产品ID返回产品的详细信息给SalesApplication。整个实现的难点在于对于SalesApplication,如何将响应的产品信息与请求的信息一一对应,即收到的产品信息如何唯一匹配发送的请求(也许先后请求了一样的产品ID,唯一匹配则需要知道返回的响应到底对应于哪一次发送的包含产品ID的请求),这里通过SessionID实现唯一匹配,架构如下图所示,包含两个队列,一个用于传输请求消息(RequiresSession为false),一个用于传输响应消息(RequiresSession为true)。

    1. sales application创建了一个用于请求的包含产品ID的消息,并将ReplyToSessionId设置成唯一的值(例如Guid);
    2. 用于请求的消息发送至请求队列中;
    3. sales application调用AcceptMessageSession等待响应消息会话,接受响应会话成功以后则可以通过会话接收消息;
    4. 服务端(Product catalog application)接收请求消息;
    5. 服务端根据产品ID获取产品信息,并创建响应消息,响应消息的SessionId设置为请求消息的ReplyToSessionId;
    6. 服务端发送响应消息;
    7. sales application接收响应消息,从消息内容中获取产品详细信息,并根据消息的SessionId匹配请求,从而对消息进行处理。

    SalesApplication代码:

    复制代码
     1             string requestQueueName = "ProductRequestQueue";
     2             string responseQueueName = "ProductResponseQueue";
     3             
     4 
     5             MessagingFactory factory = MessagingFactory.Create();
     6             QueueClient requestQueueClient = factory.CreateQueueClient(requestQueueName);
     7             QueueClient responseQueueClient = factory.CreateQueueClient(responseQueueName);
     8 
     9             string sessionId = Guid.NewGuid().ToString();
    10 
    11             BrokeredMessage requestMessage = new BrokeredMessage();
    12             requestMessage.Properties["ProductId"] = Guid.NewGuid().ToString();
    13             requestMessage.ReplyToSessionId = sessionId;
    14             requestQueueClient.Send(requestMessage);
    15             Console.WriteLine("Request Message sent. Session Id:{0}", requestMessage.ReplyToSessionId);
    16             requestMessage.Dispose();
    17 
    18             try
    19             {
    20                 MessageSession session = responseQueueClient.AcceptMessageSession(sessionId);
    21                 BrokeredMessage responseMessage = session.Receive();
    22                 if (responseMessage != null)
    23                 {
    24                     object productInfo = responseMessage.GetBody<object>();
    25                     Console.WriteLine("Response Message received. Session Id:{0}", responseMessage.SessionId);
    26                 }
    27             }
    28             catch
    29             { 
    30                 
    31             }
    32 
    33             Console.WriteLine();
    34             Console.WriteLine("Press [Enter] to exit.");
    35             Console.ReadLine();
    36             
    37             factory.Close();
    38             requestQueueClient.Close();
    39             responseQueueClient.Close();
    复制代码

    Product Catalog Application代码:

    复制代码
     1             string requestQueueName = "ProductRequestQueue";
     2             string responseQueueName = "ProductResponseQueue";
     3             NamespaceManager namespaceClient = NamespaceManager.Create();
     4             if (namespaceClient.QueueExists(requestQueueName))
     5             {
     6                 namespaceClient.DeleteQueue(requestQueueName);
     7             }
     8             if (namespaceClient.QueueExists(responseQueueName))
     9             {
    10                 namespaceClient.DeleteQueue(responseQueueName);
    11             }
    12             QueueDescription requestQueueDescription = new QueueDescription(requestQueueName)
    13             {
    14                 RequiresSession = false
    15             };
    16             namespaceClient.CreateQueue(requestQueueDescription);
    17             QueueDescription responseQueueDescription = new QueueDescription(responseQueueName)
    18             {
    19                 RequiresSession = true
    20             };
    21             namespaceClient.CreateQueue(responseQueueDescription);
    22 
    23 
    24             MessagingFactory factory = MessagingFactory.Create();
    25             QueueClient requestQueueClient = factory.CreateQueueClient(requestQueueName);
    26             QueueClient responseQueueClient = factory.CreateQueueClient(responseQueueName);
    27 
    28             while (true)
    29             {
    30                 BrokeredMessage requestMessage = null;
    31                 while ((requestMessage = requestQueueClient.Receive()) != null)
    32                 {
    33                     Console.WriteLine("Request Message received. Session Id:{0}", requestMessage.ReplyToSessionId);
    34                     string sessionId = requestMessage.ReplyToSessionId;
    35                     object productInfo = GetProductInfo(requestMessage.Properties["ProductId"].ToString());
    36                     BrokeredMessage responseMessage = new BrokeredMessage(productInfo);
    37                     responseMessage.SessionId = sessionId;
    38                     responseQueueClient.Send(responseMessage);
    39                     Console.WriteLine("Response Message sent. Session Id:{0}", responseMessage.SessionId);
    40 
    41                     requestMessage.Complete();
    42                     requestMessage.Dispose();
    43                     responseMessage.Dispose();
    44                 }
    45 
    46                 //Thread.Sleep(5 * 1000);
    47             }
    复制代码

    首先运行Product Catalog Application,因为需要先创建Queue,然后运行SalesApplication,测试结果如图所示:

    请求端:

    响应端:

    点击 这里 下载源码。

     
     
    分类: Windows Azure
  • 相关阅读:
    Leetcode单链表反转
    算法--二叉搜索树的python实现
    云服务器(阿里和腾讯)搭建网络云盘Nextcloud
    VGG16和集成模型(LeNet,CNN,Net均匀池化)比较
    git与github
    pyspider-崔庆才猫途鹰
    给 Python 添加进度条 | 给小白的 tqdm 精炼实例!
    @wraps 修饰器:让你的 Python 代码更加简短可爱 | 从简单实例来认识它
    并发和并行 | Python中实现多线程 threading 和多进程 multiprocessing
    Python格式化字符串字面值 | 被官方文档称之为『漂亮』的输出格式
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2874477.html
Copyright © 2020-2023  润新知