Today this blog post is the last article of my translation RABBITMQ, introducing RABBITMQ's C # development interface. Well, let's get to the chase.
Net/c# Client API Introduction
1. Main namespaces, interfaces and classes
The interfaces and classes that define the API for the core are defined under the Rabbitmq.client namespace:
So to use the RABBITMQ function, you need the following code
Using Rabbitmq.client;
The interfaces and classes for the "1", core API are as follows:
IModel: Represents a channel that conforms to the AMQP 0-9-1 protocol and provides a number of ways to do it
Iconnection: Represents a Connection object that conforms to the AMQP 0-9-1 protocol, and the user and RABBITMQ server connections
ConnectionFactory: You can create an instance of an Iconnection object.
Ibasicconsumer: A consumer that represents a message, or a user.
"2", other useful interfaces and classes include the following:
Defaultbasicconsumer: Typically used as a base class for consumers, if you want to write your own consumer program, you can inherit from that class.
The public namespaces "3", except for Rabbitmq.client, include:
RabbitMQ.Client.Events: Various events and event handlers as part of the client library.
Includes Eventingbasicconsumer, a consumer implementation built on C # event handlers.
RabbitMQ.Client.Exceptions: Some exception objects that are visible to the user.
All other namespaces retain private implementation details for the library, although members of the private namespace can often use the library's applications to allow developers to implement their solutions to failures or design errors found in the library implementation. An application cannot rely on any classes, interfaces, member variables, etc. that appear in a private namespace that remains stable in the version of the library.
2. Create a connection to the agent
To connect to RABBITMQ, you need to instantiate a connectionfactory and configure it to use the host name, virtual host, and credentials that you want. Then use Connectionfactory.createconnection () to open a connection. The following two code snippets are connected to the RABBITMQ node on the hostname:
ConnectionFactory factory =NewConnectionFactory (); //"Guest"/"Guest" by default, limited to localhost connectionsFactory. UserName =user; Factory. Password=Pass; Factory. VirtualHost=Vhost; Factory. HostName=HostName; Iconnection Conn=Factory. CreateConnection (); ConnectionFactory Factory=NewConnectionFactory (); Factory. Uri="Amqp://user:[email protected]:p ort/vhost"; Iconnection Conn= Factory. CreateConnection ();
because. NET clients are interpreted with a stricter AMQP 0-9-1 URI specification than other clients, so be careful when using URIs. In particular, the host part cannot be ignored, and a virtual host with a null name is not addressable. All factory properties have default values. If the property remains unassigned before the connection is created, the default value for the property is used:
Username " Guest " Password "guest" Virtual host " / " Hostname "localhost" Port 56725671
The Iconnection interface can open a channel:
IModel channel = conn. Createmodel ();
Channel channels for receiving and sending messages
3. Using message switches and queues
The client application will work with the message switch and Message Queuing (the advanced building blocks of the AMQP 0-9-1). "Message switches" and "Message Queuing" must be declared before they are used. Declaring an object of any type simply ensures that one of the names exists and, if necessary, creates it. Continuing with the previous example, the following code declares a message switch and a queue, and then binds them together.
model. Exchangedeclare (Exchangename, exchangetype.direct); false false false NULL ); null);
This declares the following two objects:
"1", non-persistent, non-automatic deletion, Exchange type "direct" of the message switch;
"2", non-persistent, non-automatic deletion, non-exclusive Message Queuing
You can customize the message switch by using additional parameters. The above code then binds the queue to the message switch using the given routing key. Note that many channel API (IModel) method overloads. Exchangedeclare a convenient and simple form with reasonable default values. There are more forms with more parameters, you can modify these defaults as needed, and take full control when needed. This "short version, long version" mode is used throughout the API.
4. Post a message
To publish the message to the message switch, use Imodel.basicpublish, as follows:
byte [] messagebodybytes = System.Text.Encoding.UTF8.GetBytes ("Hello, world! " ); null, messagebodybytes);
For fine-grained control, you can use overloaded variables to specify mandatory flags, or to specify message properties:
byte [] messagebodybytes = System.Text.Encoding.UTF8.GetBytes ("Hello, world! " ); = model. Createbasicproperties (); " Text/plain " ; 2 ; Model. Basicpublish (Exchangename, routingkey, props, messagebodybytes);
This will send a message with a send mode of 2 (persistence) and a content type of "Text/plain". For more information about the available message properties, see definition of the Ibasicproperties interface.
In the following example, we use a custom header to publish a message:
byte[] messagebodybytes = System.Text.Encoding.UTF8.GetBytes ("Hello, world!."); Ibasicproperties Props=model. Createbasicproperties (); Props. ContentType="Text/plain"; Props. DeliveryMode=2; Props. Headers=Newdictionary<string,Object>(); Props. Headers.add ("Latitude",51.5252949); Props. Headers.add ("Longitude", -0.0905493); Model. Basicpublish (Exchangename, Routingkey, props, messagebodybytes);
The following example sets the message expiration:
byte [] messagebodybytes = System.Text.Encoding.UTF8.GetBytes ( " hello, world! " = model. Createbasicproperties (); Props. ContentType = " text/plain " ; Props. DeliveryMode = 2 ; Props. Expiration = 36000000 " mode. Basicpublish (Exchangename, Routingkey, props, messagebodybytes);
5. Get personal messages ("Pull API")
To retrieve a single message, use Imodel.basicget. The returned value is an instance of Basicgetresult from which you can extract the base property and the body of the message:
BOOL false = Channel. Basicget (QueueName, noack); if NULL ) { // No message available at this time. Else { = result. basicproperties; byte [] BODY = result. Body; ...
Because Noack = False, you must also call Imodel.basicack to confirm that you have successfully received and processed the message:
... // acknowledge receipt of the message false );}
Note that using this API to get messages is less efficient. If you want RABBITMQ to push messages to the client, see the next section.
6. Retrieving mail via Subscription ("Push API")
Another way to receive messages is to use the Ibasicconsumer interface to establish a subscription. The message will then be sent automatically when it arrives without unsolicited requests. One way to achieve "consumer" is to use the convenience class Eventingbasicconsumer, which will transmit and other "consumer" life-cycle events to C # events:
var consumer = new Eventingbasicconsumer (channel); consumer. Received + = (CH, ea) => { var body = EA. Body; // ... process the message Channel. Basicack (ea. Deliverytag, false = Channel. Basicconsume (queuename, false , consumer);
Another option is to override the method according to subclass Defaultbasicconsumer, or implement Ibasicconsumer directly. You will generally want to implement the Core method Ibasicconsumer.handlebasicdeliver. More sophisticated consumers will need to implement a further approach. In particular, the Handlemodelshutdown makes the channel/connection closed. "Consumer" can also implement Handlebasiccancelok to get cancellation notice. The Defaultbasicconsumer Consumertag property can be used to retrieve the server-generated consumer tag if it is not provided to the original Imodel.basicconsume call. You can use Imodel.basiccancel to cancel an active consumer:
Channel. Basiccancel (Consumertag);
When invoking an API method, you always refer to the consumer through the "Consumer" tab, which can be generated by the client or server, as described in the AMQP 0-9-1 specification documentation.
7, "consumer" of the Concurrency considerations
In the current implementation, each Iconnection instance is supported by a background thread read from the socket, and the generated events are dispatched to the application. If the heartbeat is enabled, starting with version 3.5.0, they will be implemented in. NET Timers. Therefore, at least two threads in an application that typically use this library are active:
Application Threads
Contains the application logic and calls the Imodel method to perform the protocol operation.
I/O active thread
Hidden and fully managed by iconnection instances.
One place in the application where you can see the nature of the threading model is any callback that is registered with the application in the library. This callback includes:
Any Ibasicconsumer method
The Basicreturn event on the Imodel
Various shutdown events such as Iconnection,imodel
8. "Consumer" callback and subscription
Starting with version 3.5.0, the application callback handler can invoke blocking operations such as Imodel.queuedeclare or Imodel.basiccancel. The Ibasicconsumer callback is called at the same time. However, each channel operation command is retained. In other words, if messages A and B are routed in the same channel order, they are processed in this order. If messages A and B are routed on different channels, the messages can be processed in any order (or in parallel). By ". NET runtime, a callback that calls "consumer" in the default TaskScheduler task dispatcher.
9. Using a custom Task Scheduler
You can use the custom Task Scheduler by setting Connectionfactory.taskscheduler:
Public class customtaskscheduler:taskscheduler{ // ... }varnewnew customtaskscheduler ();
This can be used, for example, to limit the degree of concurrency through custom TaskScheduler.
10. Sharing channels in multiple threads Chanel
As a rule of thumb, imodel instances should not be used by multiple threads at the same time: the application code should maintain a clear understanding of the thread ownership of the Imodel instance. If multiple threads need access to a particular Imodel instance, the application should enforce mutexes. One way to accomplish this is to lock the instance itself for all users of Imodel:
IModel ch = retrievesomesharedimodelinstance (); Lock (CH) { ch. Basicpublish (...);}
Imodel operation error A series of symptoms including but not limited to,
Sending an invalid frame sequence online (for example, if multiple basicpublish operations are running at the same time) and/or throwing a NotSupportedException exception from a method in class Rpccontinuationqueue, prompting "the request of the pipeline is forbidden" Pipelining of requests Forbidden "" occurs when multiple AMQP 0-9-1 synchronization operations (such as Exchangedeclare) are running concurrently.
11. Handling Non-routable messages
If a message with the Force flag is published but fails to be delivered, the agent returns the message to the sending client (via the Basic.return AMQP 0-9-1 command). To obtain this type of notification, the client can subscribe to the Imodel.basicreturn event. If there is no listener attached to the event, the returned message is silently discarded.
Model. Basicreturn + = new RabbitMQ.Client.Events.BasicReturnEventHandler (...);
The Basicreturn event is triggered if the client sends a message identified as "mandatory" to "message switch Exchange" of type "Direct", but the exchange is not yet bound to a message queue.
12. Disconnect from RABBITMQ
To disconnect, simply close the channel and connect:
Channel. Close ("Goodbye"); Conn. Close ();
Note that it is good practice to close the channel, but it is not necessary-it will be done automatically when the underlying connection is closed. In some cases, you may want the last open channel on the connection to close when the connection is closed, for this purpose, set the Iconnection.autoclose property to True, but only after the first channel is created:
Iconnection conn ==true;
When AutoClose is true, the last closed channel will also cause the connection to close. If set to true before any channels are created, the connection will be closed at that time.
Well, temporarily translated to this bar, in fact, there are some not translated, temporarily not translated, there is time to continue.
Then put the original address, want to see the full can be viewed through the connection. The address is as follows: http://www.rabbitmq.com/dotnet-api-guide.html
RABBITMQ Series Tutorial VII: Introduction to the RABBITMQ C # client API