How to use the C# Request-Reply API.
How to use the C# Request-Reply API.
Requesters and Repliers provide a way to use the Request-Reply communication pattern on top of the DDS entities. An application uses a Requester to send requests to a Replier; another application using a Replier receives a request and can send one or more replies for that request. The Requester that sent the request (and only that one) will receive the reply (or replies).
- Note
- To use the C# Request-Reply API, add the following NuGet package to your C# project:
Rti.ConnextDds.RequestReply
RTI Connext uses DDS data types for sending and receiving requests and replies. Valid types are those generated by the rtiddsgen code generator, the DDS built-in types, and DynamicData. Refer to the User's Manual and the Modern C++ Request-Reply Examples for more information.
The rticonnextdds-examples GitHub repository also provides a full example application using Request-Reply.
Sections:
The IDL definitions of the RandomNumberRequest
and RandomNumberReply
types used in the examples are the following:
struct RandomNumberRequest {
int minValue;
int maxValue;
};
struct RandomNumberReply {
int value;
};
};
Creation of a Requester and a Replier
Example: Create a basic Requester
factory.CreateParticipant(domainId: 0);
Requester<RandomNumberRequest, RandomNumberReply> requester =
participant.BuildRequester<RandomNumberRequest, RandomNumberReply>()
.WithServiceName("RandomNumber")
.Create();
Singleton that manages the creation of DomainParticipant objects.
Definition: DomainParticipantFactory.cs:25
static DomainParticipantFactory Instance
Gets the singleton instance of this class.
Definition: DomainParticipantFactory.cs:39
Container for all other Entity objects.
Definition: DomainParticipant.cs:39
Contains DomainParticipant and related classes.
Definition: DomainParticipant.cs:33
Contains the RTI Connext DDS C# API.
Definition: AsyncWaitSetProperty.cs:18
Contains the RTI Connext C# API.
Definition: Logger.cs:20
Example: Create a basic Replier
factory.CreateParticipant(domainId: 0);
var replier = participant.BuildReplier<RandomNumberRequest, RandomNumberReply>()
.WithServiceName("RandomNumber")
.Create();
Example: Configure a Requester or Replier with additional properties
var publisher = participant.CreatePublisher();
var readerQos = participant.DefaultDataReaderQos
.WithHistory(policy => policy.Kind =
HistoryKind.KeepAll)
.WithResourceLimits(policy => policy.MaxSamples = LengthUnlimited.Value);
var writerQos = participant.DefaultDataWriterQos
.WithHistory(policy => policy.Kind =
HistoryKind.KeepAll)
.WithResourceLimits(policy => policy.MaxSamples = 10);
var requester = participant.BuildRequester<RandomNumberRequest, RandomNumberReply>()
.WithServiceName("RandomNumber")
.WithPublisher(publisher)
.WithDataReaderQos(readerQos)
.WithDataWriterQos(writerQos)
.Create();
ReliabilityKind
Kinds of reliability
Definition: Reliability.cs:190
HistoryKind
History kinds
Definition: History.cs:167
Communication between a Requester and a Replier
Example: Send requests
var request = new RandomNumberRequest(10, 1000);
requester.SendRequest(request);
using var replies = requester.ReceiveReplies(1, Duration.FromSeconds(5));
foreach (var reply in replies.ValidData())
{
System.Console.WriteLine($"Reply received: {reply.Value}");
}
Example: Reply to received requests
int receivedRequests = await replier.WaitForRequestsAsync(2, cancellationToken);
if (receivedRequests >= 2)
{
LoanedSamples<RandomNumberRequest> requests = replier.TakeRequests();
var randomNumber = new System.Random();
foreach (var request in requests)
{
if (request.Info.ValidData)
{
var reply = new RandomNumberReply(
randomNumber.Next(request.Data.MinValue, request.Data.MaxValue));
replier.SendReply(reply, request.Info);
}
}
}
Example: Correlate requests and their respective replies
var request1 = new RandomNumberRequest(0, 100);
var request2 = new RandomNumberRequest(200, 300);
SampleIdentity requestId1 = requester.SendRequest(request1);
SampleIdentity requestId2 = requester.SendRequest(request2);
if (!requester.WaitForReplies(1, requestId2, Duration.FromSeconds(5)))
{
System.Console.WriteLine("No reply for request 2");
}
else
{
using var replies = requester.TakeReplies(requestId2);
foreach (var reply in replies)
{
System.Diagnostics.Debug.Assert(
request2.Equals(reply.Info.OriginalPublicationVirtualSampleIdentity));
}
}
Example: Use a handler to process available requests
static void customHandler(Replier<RandomNumberRequest, RandomNumberReply> replier)
{
using var requests = replier.TakeRequests();
var randomNumber = new System.Random();
foreach (var request in requests)
{
if (request.Info.ValidData)
{
var randomNumberRequest = new RandomNumberReply(
randomNumber.Next(request.Data.MinValue, request.Data.MaxValue));
replier.SendReply(randomNumberRequest, request.Info);
}
}
}
replier.RequestsAvailable += customHandler;
replier.RequestsAvailable -= customHandler;
Using ContentFilteredTopics to filter requests
Example: Create a ContentFilteredTopic and make the Replier use it for requests
var requestTopic = participant.CreateTopic<RandomNumberRequest>("RequestsTopic");
var cft = participant.CreateContentFilteredTopic(
"RequestsCft",
requestTopic,
new Filter("minvalue > 100"));
var requester =
participant.BuildRequester<RandomNumberRequest, RandomNumberReply>()
.WithTopicNames("RequestsTopic", "RepliesTopic")
.Create();
var filteringReplier =
participant.BuildReplier<RandomNumberRequest, RandomNumberReply>()
.WithTopicNames("RequestsCft", "RepliesTopic")
.Create();
requester.SendRequest(new RandomNumberRequest(50, 100));
requester.SendRequest(new RandomNumberRequest(150, 200));
using var requests = filteringReplier.ReceiveRequests(1, Duration.FromSeconds(5));
Using DynamicData
This example assumes that you have the DynamicType definition of the request type (randomNumberRequestType). See also DynamicData examples to see the different ways to create or get a DynamicType.
Example: Use DynamicData
var requester = participant.BuildRequester<DynamicData, RandomNumberReply>()
.WithServiceName("RandomNumber")
.WithRequestDynamicType(randomNumberRequestType)
.Create();
var request = new DynamicData(randomNumberRequestType);
request.SetValue("MinValue", 10);
request.SetValue("MaxValue", 100);
requester.SendRequest(request);
Asynchronous Wait
Example: Wait for samples asynchronously
var count = await replier.WaitForRequestsAsync(1, cancellationToken);
if (count == 0)
{
throw new System.TimeoutException("No requests received");
}
using var requests = replier.TakeRequests();
foreach (var request in requests)
{
if (request.Info.ValidData)
{
replier.SendReply(
new RandomNumberReply(new System.Random().Next()),
request.Info);
}
}
Using a SimpleReplier
Example: Use a SimpleReplier instead of a regular Replier for simplified request handling
var simpleReplier =
participant.BuildSimpleReplier<RandomNumberRequest, RandomNumberReply>()
.WithServiceName("SimpleReplierExample")
.WithRequestHandler(
request =>
{
var randomNumber = new System.Random().Next(
request.MaxValue,
request.MinValue);
return new RandomNumberReply(randomNumber);
})
.Create();