SDK (.net)
Downloading the SDK
Install-Package Pharmx.DataSync.SDK.Dotnet -Version 0.1.32
Or via nuget: https://www.nuget.org/packages/Pharmx.DataSync.SDK.Dotnet/
Instantiating the client
First instantiate the data sync client, providing the access keys, site id, and optional service id.
var client = new DataSyncClient(
siteID: "112",
serviceID: null,
inboundKey: new DataSyncClientKey()
{
SharedAccessKeyName = "112",
SharedAccessKey = "***************************="
},
outboundKey: new DataSyncClientKey()
{
SharedAccessKeyName = "112",
SharedAccessKey = "***************************="
},
environment: Environment.Test
);
Sending Messages
Constructing a message
New up a DataSyncMessage object, set the message type, message direction, and complete the necessary fields. All data sync messages in effect share a single object schema.
var message = new DataSyncMessage() {
MessageType = Enums.MessageType.RetailTransaction,
MessageDirection = Enums.MessageDirection.Inbound,
RetailTransaction = new Transactions.RetailTransaction()
{
LineItems = new List<LineItem> {
new LineItem()
{
Sale = new Sale()
{
Quantity = 5,
UnitListPrice = 2.00M
}
}
},
Total = new Transactions.Total()
{
Amount = 10.00M
}
}
};
Validating a message
When sending a message, depending on the context pharmx will run several hundred validation rules, this may result in your message not being sent to the destination, but instead sent back to you, in the form of an error. To avoid this round-trip scenario, as well as to provide a cleaner response to the user, and/or error recovery processes, we recommend validating the object before it is sent.
The data sync client has a method that validates a message, and returns an isvalid response, as well as an array of validation errors. Use these control the message flow.
var validationresult = client.ValidateDataSyncMessage(message);
if (validationresult.IsValid == true)
{
// Proceed
}
else
{
// Reverse/Exit
Console.WriteLine(validationresult.ToString());
}
Sending a message
The DataSync client has two methods to send messages, one of them is to send a single message, the other is to send a batch of messages. Both of them can be used in high-flow/low latency scenarios, however the batch method does use less network bandwidth (as headers are shared). Batching generally will put between 50 and 300 messages together as a single network request. The consumer will recieve the same stream regardless of whether a batch or a single message is sent.
Send Single message
await client.SendMessageAsync(message);
Send a batch of messages
var batchOfMessages = new List<DataSyncMessage>();
batchOfMessages.Add(message);
batchOfMessages.Add(message);
batchOfMessages.Add(message);
await client.SendBatchAsync(batchOfMessages);
Receiving Messages
Intro two choices
There are two methods of recieving messages, each with their own use case.
Receive Message Batch
The easiest way to receive a batch of messages is in batch, although we only recommend this in limited circumstances where latency and reliability is not a priority.
var messageBatch = await client.ReceiveMessageAsync(limitCount: 1000, limitTime: 60);
The above command will connect to the pharmx network and download a 1000 messages, if 1000 messages do not exist on the endpoint, the request will wait a total of 60 seconds before returning a partial batch (which could be 0 messages.)
In this method you are forced to choose between an optimal batch size and wait time, this however can still be useful if your work flow is to download a 1,000 messages or 1 second, and then save the 1,000 messages to the database, databases like sql server, prefer batched writes for maximum throughput, example below.
Please keep in mind with the below code, you can recieve much more than a thousand messages per second. (It is ‘a thousand messages or 1 second, whichever comes first’.)
Example. recieving a thousand messages (or 1 second) and persisting for later processing
while (true)
{
var messageBatch = await client.ReceiveMessageAsync(limitCount: 1000, limitTime: 1);
database.AddRange(messageBatch);
try
{
await database.SaveChangesAsync();
}
catch (Exception e)
{
// These messages will be lost forever if this is unhandled
// So try to put them somwhere, where they can be retried.
}
}
We do not recommend trying to processing business logic in this fashion, when the 1000 messages is pulled off the queue, they are immediately marked as completed on the pharmx network and removed. We therefor recommend that you pull them off the queue and straight into a persistent format, where you subsequently re-order, and process.
Receive Message Stream
This is the preferred method of recieving messages where you want to handle inbound messages with high concurrency, low latency, and high-reliability.
First you will want to register two method handlers, and then call StartProcessingAsync.
client.ProcessDataSyncMessageAsync += Client_ProcessDataSyncMessageAsync1;
client.ProcessDataSyncErrorAsync += Client_ProcessDataSyncErrorAsync;
await client.StartProcessingAsync();
The client will then start feeding events in real-time to the ProcessDataSyncMessage method, if any unhandled exceptions occur (in your code, not on the network), then the second method (ProcessDataSyncError) will be triggered.
Below is an example, of how you might handle a message:
private static async Task Client_ProcessDataSyncMessageAsync1(DataSyncMessageReceivedEvent dataSyncMessageEvent)
{
var message = dataSyncMessageEvent.DataSyncMessage;
try
{
await DoSomeKindOfWorkHereAsync(message);
await dataSyncMessageEvent.Session.CompleteMessageAsync(dataSyncMessageEvent.Session.Message);
}
catch (Exception e)
{
// Save message to an error recovery workflow.
}
}
// Here an error has occcurred within your client.
// This could be due to a version mismatch between the SDK and the PharmX Portal
private static Task Client_ProcessDataSyncErrorAsync(Azure.Messaging.ServiceBus.ProcessErrorEventArgs arg)
{
// So we have two choices:
// either throw an exception, which cause the pharmx network to try and send this message to another reciever or wait a small interval of time and send back to this same reciever.
// Or save the message to an internal error handling workflow
throw new NotImplementedException();
}