今天这篇博文是我翻译的RabbitMQ的最后一篇文章了,介绍一下RabbitMQ的C#开发的接口。好了,言归正传吧。

Net/C# 客户端 API简介

主要的命名空间,接口和类

定义核心的API的接口和类被定义在RabbitMQ.Client这个命名空间下面:

所以要想使用RabbitMQ的功能,需要以下代码

  1. using RabbitMQ.Client;

核心API的接口和类

IModel:表示一个符合AMQP 0-9-1 协议的通道,并且提供了很多的操作方法

IConnection:表示一个符合AMQP 0-9-1协议的连接对象,用户和RabbitMQ 服务端的连接

ConnectionFactory:可以创建一个IConnection对象的实例。

IBasicConsumer:表示一个消息的消费者,或者是使用者。

其他有用的接口和类

DefaultBasicConsumer:通常用作消费者的基类,如果要编写自己的消费者程序,可以从该类继承。

除RabbitMQ.Client之外的公共命名空间

RabbitMQ.Client.Events:作为客户端库一部分的各种事件和事件处理程序。包括EventingBasicConsumer,一个基于C#事件处理程序构建的消费者实现。

RabbitMQ.Client.Exceptions: 对用户可见的一些异常对象。

所有其他命名空间都保留用于库的私有实现细节,尽管私有命名空间的成员通常可以使用该库的应用程序使用,以便允许开发人员实现其在库实现中发现的故障或设计错误的解决方法。 应用程序不能依赖于在库的版本中保持稳定的私有命名空间中出现的任何类,接口,成员变量等。

创建到代理的连接

要连接到RabbitMQ,需要实例化一个ConnectionFactory并将其配置为使用所需的主机名,虚拟主机和凭据。 然后使用ConnectionFactory.CreateConnection()打开一个连接。 以下两个代码片段连接到hostName上的RabbitMQ节点:

  1. ConnectionFactory factory = new ConnectionFactory();
  2. // "guest"/"guest" by default, limited to localhost connections
  3. factory.UserName = user;
  4. factory.Password = pass;
  5. factory.VirtualHost = vhost;
  6. factory.HostName = hostName;
  7. IConnection conn = factory.CreateConnection();
  8.  
  9. ConnectionFactory factory = new ConnectionFactory();
  10. factory.Uri = "amqp://user:pass@hostName:port/vhost";
  11. IConnection conn = factory.CreateConnection();

由于.NET客户端使用比其他客户端更严格的AMQP 0-9-1 URI规范解释,因此在使用URI时必须小心。 特别是,主机部分不能被忽略,具有空名称的虚拟主机不可寻址。 所有出厂属性都有默认值。 如果属性在创建连接之前保持未分配,则将使用属性的默认值:

  1. Username
  2. "guest"
  3. Password
  4. "guest"
  5. Virtual host
  6. "/"
  7. Hostname
  8. "localhost"
  9. port
  10. 是针对一般而言的连接, 是针对 TLS 连接的

IConnection接口可以打开一个通道:

  1. IModel channel = conn.CreateModel();

通道Channel用于接收和发送消息

使用消息交换机和队列

客户端应用程序将与消息交换机和消息队列(AMQP 0-9-1的高级构建块)配合工作。 【消息交换机】和【消息队列】在使用之前必须先声明他们。 声明任何类型的对象只是确保其中一个名称存在,如有必要,创建它。 继续前面的例子,以下代码声明一个消息交换机和一个队列,然后将它们绑定在一起。

  1. model.ExchangeDeclare(exchangeName, ExchangeType.Direct);
  2. model.QueueDeclare(queueName, false, false, false, null);
  3. model.QueueBind(queueName, exchangeName, routingKey, null);

这将声明了以下两个对象:

【1】、非持久、非自动删除的、交换类型为“direct”的消息交换机;

【2】、非持久、非自动删除、非排他的消息队列

可以通过使用附加参数来定制消息交换机。 然后,上面的代码使用给定的路由键将队列绑定到消息交换机。 请注意,许多通道API(IModel)方法重载。 ExchangeDeclare方便的简单形式使用合理的默认值。 还有更多的表单具有更多的参数,可以根据需要修改这些默认值,并在需要时进行完全控制。 在整个API中使用这种“短版本,长版本”模式。

发布消息

要将消息发布到消息交换机,请使用IModel.BasicPublish,如下所示:

  1. byte[] messageBodyBytes = System.Text.Encoding.UTF8.GetBytes("Hello, world!");
  2. model.BasicPublish(exchangeName, routingKey, null, messageBodyBytes);

为了精细控制,您可以使用重载变量来指定强制标志,或指定消息属性:

  1. byte[] messageBodyBytes = System.Text.Encoding.UTF8.GetBytes("Hello, world!");
  2. IBasicProperties props = model.CreateBasicProperties();
  3. props.ContentType = "text/plain";
  4. props.DeliveryMode = ;
  5. model.BasicPublish(exchangeName,
  6. routingKey, props,
  7. messageBodyBytes);

这将发送一个带有发送模式为2(持久性)和内容类型是“text / plain”的消息。 有关可用消息属性的更多信息,请参阅IBasicProperties接口的定义。

在以下示例中,我们使用自定义标头发布消息:

  1. byte[] messageBodyBytes = System.Text.Encoding.UTF8.GetBytes("Hello, world!");
  2.  
  3. IBasicProperties props = model.CreateBasicProperties();
  4. props.ContentType = "text/plain";
  5. props.DeliveryMode = ;
  6. props.Headers = new Dictionary<string, object>();
  7. props.Headers.Add("latitude", 51.5252949);
  8. props.Headers.Add("longitude", -0.0905493);
  9.  
  10. model.BasicPublish(exchangeName,
  11. routingKey, props,
  12. messageBodyBytes);

下面的示例设置消息过期:

  1. byte[] messageBodyBytes = System.Text.Encoding.UTF8.GetBytes("Hello, world!");
  2.  
  3. IBasicProperties props = model.CreateBasicProperties();
  4. props.ContentType = "text/plain";
  5. props.DeliveryMode = ;
  6. props.Expiration = ""
  7.  
  8. mode.BasicPublish(exchangeName,
  9. routingKey, props,
  10. messageBodyBytes);

获取个人消息(“拉API”)

要检索单个消息,请使用IModel.BasicGet。 返回的值是BasicGetResult的实例,可以从中提取基本属性和消息体:

  1. bool noAck = false;
  2. BasicGetResult result = channel.BasicGet(queueName, noAck);
  3. if (result == null) {
  4. // No message available at this time.
  5. } else {
  6. IBasicProperties props = result.BasicProperties;
  7. byte[] body = result.Body;
  8. ...

由于noAck = false,您还必须调用IModel.BasicAck来确认您已成功接收并处理该消息:

  1. ...
  2. // acknowledge receipt of the message
  3. channel.BasicAck(result.DeliveryTag, false);
  4. }

请注意,使用此API获取消息效率相对较低。 如果您希望RabbitMQ将消息推送给客户端,请参阅下一节。

通过订阅检索邮件(“推送API”)

   接收消息的另一种方法是使用IBasicConsumer接口建立订阅。 然后,消息将在其到达时自动发送,而不必主动请求。 实现【消费者】的一种方法是使用便利类EventingBasicConsumer,它将传送和其他【消费者】生命周期事件以C#事件:

  1. var consumer = new EventingBasicConsumer(channel);
  2. consumer.Received += (ch, ea) =>
  3. {
  4. var body = ea.Body;
  5. // ... process the message
  6. channel.BasicAck(ea.DeliveryTag, false);
  7. };
  8. String consumerTag = channel.BasicConsume(queueName, false, consumer);

另一个选项是根据子类DefaultBasicConsumer,覆盖方法,或者直接实现IBasicConsumer。 你一般会想实现核心方法IBasicConsumer.HandleBasicDeliver。 更复杂的消费者将需要实施进一步的方法。 特别地,HandleModelShutdown使通道/连接关闭。 【消费者】还可以实现HandleBasicCancelOk以获得取消通知。 DefaultBasicConsumer的ConsumerTag属性可用于检索服务器生成的使用者标签,如果没有提供给原始的IModel.BasicConsume调用。 您可以使用IModel.BasicCancel取消活跃的消费者:

  1. channel.BasicCancel(consumerTag);

在调用API方法时,您总是通过【消费者】标签来引用【消费者】,【消费者】标签可以是客户端或服务器生成的,如AMQP 0-9-1规范文档中所述。

【消费者】的并发注意事项

在当前实现中,每个IConnection实例都由一个从套接字读取的后台线程支持,并将生成的事件分派到应用程序。 如果启用了心跳,则从3.5.0版开始,它们将以.NET定时器方式实现。 因此,通常使用此库的应用程序中至少有两个线程处于活动状态:

应用程序线程

包含应用程序逻辑,并调用IModel方法来执行协议操作。

I / O活动线程

隐藏并由IConnection实例完全管理。

在应用程序中可以看到线程模型的本质的一个地方是在库中的应用程序注册的任何回调。 这种回调包括:

任何IBasicConsumer方法
     在IModel上的BasicReturn事件
     IConnection,IModel等各种关机事件

【消费者】回调和订阅

从版本3.5.0开始,应用程序回调处理程序可以调用阻塞操作(如IModel.QueueDeclare或IModel.BasicCancel)。 IBasicConsumer回调同时被调用。 但是,每通道操作命令被保留。 换句话说,如果消息A和B按照同一个频道的顺序传送,则按照此顺序进行处理。 如果消息A和B在不同的信道上传送,则可以以任何顺序(或并行)处理消息。 由【.NET运行时】提供的、默认的TaskScheduler的任务分发器中调用【消费者】的回调

使用自定义任务计划程序

通过设置ConnectionFactory.TaskScheduler可以使用自定义任务调度程序:

  1. public class CustomTaskSchedulerTaskScheduler
  2. {
  3. // ...
  4. }
  5.  
  6. var cf = new ConnectionFactory();
  7. cf.TaskScheduler = new CustomTaskScheduler();

例如,这可以用于通过自定义TaskScheduler来限制并发程度。

在多线程中共享通道Chanel

作为经验法则,IModel实例不应同时被多个线程使用:应用程序代码应该保持对IModel实例的线程所有权的清晰认识。 如果多个线程需要访问特定的IModel实例,应用程序应该强制执行互斥。 实现此目的的一种方法是为IModel的所有用户锁定实例本身:

  1. IModel ch = RetrieveSomeSharedIModelInstance();
  2. lock (ch) {
  3. ch.BasicPublish(...);
  4. }

IModel操作错误一系列的症状包括但不限于,

在线上发送无效帧序列(例如,如果同时运行多个BasicPublish操作,则发生)和/或从类RpcContinuationQueue中的方法抛出NotSupportedException异常,提示“管道的请求是被禁止的【Pipelining of requests forbidden】”(在同时运行多个AMQP 0-9-1同步操作(如ExchangeDeclare)的情况下发生)。

处理不可路由的消息

如果发布了一个设置了“强制”标志的消息,但未能送达,则代理将消息返回给发送的客户端(通过basic.return AMQP 0-9-1命令)。 要获得此类通知,客户端可以订阅IModel.BasicReturn事件。 如果没有附加事件的监听器,则返回的消息将被静默地丢弃。

  1. model.BasicReturn +=
  2. new RabbitMQ.Client.Events.BasicReturnEventHandler(...);

如果客户端把一条标识为“mandatory”的消息发送到了类型为【Direct】的【消息交换机Exchange】,但是这个exchange还没有绑定到一个消息队列的时候,BasicReturn事件就会被触发

从RabbitMQ断开连接

要断开连接,只需关闭通道和连接:

  1. channel.Close(, "Goodbye");
  2. conn.Close();

请注意,关闭通道是很好的做法,但不是必要的 - 当底层连接关闭时,它将自动完成。 在某些情况下,您可能希望连接上的最后一个打开的通道关闭的时候连接也关闭, 要实现此目的,请将IConnection.AutoClose属性设置为true,但仅在创建第一个通道后:

  1. IConnection conn = factory.CreateConnection(...);
  2. IModel channel = conn.CreateModel();
  3. conn.AutoClose = true;

当AutoClose为true时,最后关闭的通道也将导致连接关闭。 如果在创建任何通道之前设置为true,则连接将在那时关闭。

好了,暂时翻译到此吧,其实还有一些没翻译完,暂时就不翻译了,有时间再继续。

再把原文的地址贴出来,想看完整的可以通过连接浏览。地址如下:http://www.rabbitmq.com/dotnet-api-guide.html

【c#】RabbitMQ学习文档(七)C# API的更多相关文章

  1. 【c#】RabbitMQ学习文档(一)Hello World

    一.简介 RabbitMQ是一个消息的代理器,用于接收和发送消息,你可以这样想,他就是一个邮局,当您把需要寄送的邮件投递到邮筒之时,你可以确定的是邮递员先生肯定会把邮件发送到需要接收邮件的人的手里,不 ...

  2. 【c#】RabbitMQ学习文档(六)RPC(远程调用)

    远程过程调用(Remote Proceddure call[RPC]) (本实例都是使用的Net的客户端,使用C#编写) 在第二个教程中,我们学习了如何使用工作队列在多个工作实例之间分配耗时的任务. ...

  3. 【c#】RabbitMQ学习文档(四)Routing(路由)

    (使用Net客户端) 在上一个教程中,我们构建了一个简单的日志系统,我们能够向许多消息接受者广播发送日志消息. 在本教程中,我们将为其添加一项功能 ,这个功能是我们将只订阅消息的一个子集成为可能. 例 ...

  4. 【c#】RabbitMQ学习文档(五)Topic(主题。通配符模式)

    (本实例都是使用的Net的客户端,使用C#编写),说明,中文方括号[]表示名词. 在上一个教程中,我们改进了我们的日志记录系统. 没有使用只能够进行虚拟广播的[Fanout]交换机,而是使用了[Dir ...

  5. 【c#】RabbitMQ学习文档(三)Publish/Subscribe(发布/订阅)

    (本教程是使用Net客户端,也就是针对微软技术平台的) 在前一个教程中,我们创建了一个工作队列.工作队列背后的假设是每个任务会被交付给一个[工人].在这一部分我们将做一些完全不同的事情--我们将向多个 ...

  6. 【c#】RabbitMQ学习文档(二)Work Queues(工作队列)

        今天开始RabbitMQ教程的第二讲,废话不多说,直接进入话题.   (使用.NET 客户端 进行事例演示)          在第一个教程中,我们编写了一个从命名队列中发送和接收消息的程序. ...

  7. Openstack api 学习文档 & restclient使用文档

    Openstack api 学习文档 & restclient使用文档 转载请注明http://www.cnblogs.com/juandx/p/4943409.html 这篇文档总结一下我初 ...

  8. Openstack python api 学习文档 api创建虚拟机

    Openstack python api 学习文档 转载请注明http://www.cnblogs.com/juandx/p/4953191.html 因为需要学习使用api接口调用openstack ...

  9. RabbitMq 技术文档

    RabbitMq 技术文档 目录 1 AMQP简介 2 AMQP的实现 3 RabbitMQ简介 3.1 概念说明 3.2 消息队列的使用过程 3.3 RabbitMQ的特性 4 RabbitMQ使用 ...

随机推荐

  1. 处理Python2.7读写文件中的中文乱码问题

    1.设置默认编码 在Python代码中的任何地方出现中文,编译时都会报错,这时可以在代码的首行添加相应说明,明确utf-8编码格式,可以解决一般情况下的中文报错.当然,编程中遇到具体问题还需具体分析啦 ...

  2. AGC001F - Wide Swap

    Description 给你一个长度为$n$的排列,每次可以交换$|i-j|\geq K$并且$|a_i-a_j|=1$的数对,问你经过若干次变换后最小字典序的排列是啥 Solution 对$a$做一 ...

  3. c# winform打印excel(使用NPOI+Spire.xls+PrintDocument直接打印excel)

    前言 c#做winform程序要求生成并打印Excel报告,为了不安装Office相应组件,我选择了NPOI来生成Excel报告,用winform的PrintDocument控件来触发打印操作,而难点 ...

  4. c++链表基本操作

    #include <stdlib.h> #include <malloc.h> #include <stdio.h> typedef struct Node { i ...

  5. python函数用法

    一.定义函数 形参:函数完成一项工作所需要的信息,在函数定义时完成 实参:调用函数时传递给函数的信息 二.传递实参 1.位置实参:每个实参都关联到函数定义中的一个形参 示例: def describe ...

  6. pygame学习

    http://eyehere.net/2011/python-pygame-novice-professional-3/ http://www.pygame.org/docs/ref/event.ht ...

  7. node01

    ---恢复内容开始--- 1.node初体验 安装完成node,写好相应的js代码后,在cmd中node 文件名即可完成编译执行过程. 2.尝试使用node搭建一个简单服务器 //引入http模块 c ...

  8. Linux了解知识点

    Linux知识点   1.linux系统内核最早由芬兰大学生linus Torvalds开发. 2.Linux主要用于服务器端和嵌入式两个领域. 3.Linux的特点:开放性.多用户.多任务.良好的用 ...

  9. 把一下程序中的print()函数改写成

    源代码: #include <iostream> using namespace std; void print( int w ) { ; i <= w ; i++ ) { ; j ...

  10. LeetCode编程训练 - 拓扑排序(Topological Sort)

    拓扑排序基础 拓扑排序用于解决有向无环图(DAG,Directed Acyclic Graph)按依赖关系排线性序列问题,直白地说解决这样的问题:有一组数据,其中一些数据依赖其他,问能否按依赖关系排序 ...