Advanced Options
For more advanced configuration, you can use the NatsOpts
class to configure the connection to the NATS server.
For example, you can hook your logger to NatsClient
to make sure all is working as expected or
to get help diagnosing any issues you might have:
(For this example, you need to add Microsoft.Extensions.Logging.Console from Nuget.)
using ILoggerFactory loggerFactory = LoggerFactory.Create(configure: builder => builder.AddConsole());
NatsOpts opts = new NatsOpts { LoggerFactory = loggerFactory };
await using NatsClient nc = new NatsClient(opts);
NatsClient vs NatsConnection
NatsClient
is a high-level API that wraps NatsConnection
and provides a more user-friendly interface to interact with the NATS server.
It is the recommended way to interact with the NATS server for beginners.
However, if you need to access the underlying NatsConnection
instance,
you can do so by using the Connection
property of NatsClient
or by creating a new instance of NatsConnection
.
So, What's the Difference?
NatsClient
implements INatsClient
and provides a high-level APIs, and also
sets up the serializers to use the expected formats for message types like int
,
string
, byte[]
, and data classes for ad hoc JSON serialization.
NatsConnection
is the underlying class that manages the connection to the NATS server.
It provides more advanced APIs and allows you to configure the connection in more detail.
NatsConnection
implements INatsConnection
which extends INatsClient
with advanced APIs,
so you can use it as a NatsClient
instance without any changes to your code. When you
instantiate a NatsConnection
with default options, you would only have basic serialization
for int
, string
, and byte[]
types, and you would need to set up the serializers for your data classes
if you want to use e.g., JSON serialization.
The other difference is that NatsClient
sets SubPendingChannelFullMode
internal channel option to
BoundedChannelFullMode.Wait
to avoid dropping messages when the subscriber's internal channel is full.
This is a good default for most cases, but you can change it by setting the SubPendingChannelFullMode
option
in NatsClient
constructor.
NatsOpts opts = new NatsOpts
{
// You need to set pending in the constructor and not use
// the option here, as it will be ignored.
SubPendingChannelFullMode = BoundedChannelFullMode.DropOldest,
// Your custom options
SerializerRegistry = new MyProtoBufSerializerRegistry(),
// ...
};
await using NatsClient nc = new NatsClient(opts, pending: BoundedChannelFullMode.DropNewest);
You can also use the NatsConnection
class directly.
NatsOpts opts = new NatsOpts
{
// Your custom options
};
await using NatsConnection nc = new NatsConnection(opts);
Which One Should I Use?
If you are new to NATS, you should use NatsClient
as it provides a more user-friendly interface
with sensible defaults especially for serialization.
If you need more control over the connection options, AOT deployments, or custom serializers,
you should use NatsConnection
.
See also serialization for more information on how to set up custom serializers.
Note
Every NatsClient
(and the underlying NatsConnection
)
instance is a TCP connection to a NATS server.
Typically an application will only need one
connection, and many subscriptions and publishers would share that same connection. Connections are relatively
heavyweight and expensive to create while
subscriptions and publishers are lightweight internal NATS protocol handlers.
NATS.Net should be able to handle large numbers of subscriptions
and publishers per connection.
Subscriptions with Lower Level Control
The
SubscribeAsync()
method is a convenient way to subscribe to a subject and receive messages without much effort.
If you need more control over how subscription is handled, you can use the
SubscribeCoreAsync()
method instead.
await using NatsConnection nc = new NatsConnection();
// Connections are lazy, so we need to connect explicitly
// to avoid any races between subscription and publishing.
await nc.ConnectAsync();
await using INatsSub<int> sub = await nc.SubscribeCoreAsync<int>("foo");
for (int i = 0; i < 10; i++)
{
Console.WriteLine($" Publishing {i}...");
await nc.PublishAsync<int>("foo", i);
}
// Signal subscription to stop
await nc.PublishAsync<int>("foo", -1);
// Messages have been collected in the subscription internal channel
// now we can drain them
await foreach (NatsMsg<int> msg in sub.Msgs.ReadAllAsync())
{
Console.WriteLine($"Received {msg.Subject}: {msg.Data}\n");
if (msg.Data == -1)
break;
}
// We can unsubscribe from the subscription explicitly
// (otherwise dispose will do it for us)
await sub.UnsubscribeAsync();
Round Trip Time (RTT)
PingAsync()
is somewhat a
special method in all NATS clients, mostly referred to as rtt
. It is used to send a ping to the server and
receive a pong back while measuring the round trip time. Since it waits for the server to respond, as a side effect,
it also flushes the outgoing buffers.
Remember that every NatsConnection
instance is a single TCP connection
and all the calls sent to the server are
essentially sent back to back after they're picked up from internal queues and buffers.
await using NatsClient nc = new NatsClient();
TimeSpan rtt = await nc.PingAsync();
Console.WriteLine($"RTT to server: {rtt}");
Note
NatsConnection
establishes the first server connection when the first call to subscribe or publish is made.
You can also call the ConnectAsync()
method explicitly to establish the connection before any other calls are made.
What's Next
- Serialization is the process of converting an object into a format that can be stored or transmitted.
- Security is an important aspect of any distributed system. NATS provides a number of security features to help you secure your applications.
- AOT Deployment is a way to deploy your applications as native platform executables, which produces faster startup times and better performance in most cases.