Last updated: August 2, 2024 | Originally published: February 26, 2020
We are very excited to announce the availability of a brand new Lightstreamer client API for Microsoft .NET Standard specifications.
What’s new
The new library introduces full support for the Unified Client API model, which we have been introducing in all Lightstreamer client libraries for some years now (indeed the first “Unified” library was JavaScript 6.0). The big advantage of using the Unified API is the same consistent interface and behavior are guaranteed across different client platforms. In other words, the same abstractions and internal mechanisms are provided for very different platforms (Web, Android, Java, iOS, .NET, Node.js, etc.), while respecting the conventions, styles, and best practice of each platform.
Furthermore, the new library has transitioned to the TLCP protocol for the communication with the Lightstreamer server. The TLCP protocol is designed around unifying principles like simplicity of parsing, uniformity of responses, and support for multiple transports. Indeed, the inclusion of TLCP opens the way for the support of WebSockets as primary transport.
WebSockets provide a persistent, full-duplex communication channel between the client and the Server, reducing connection overhead to a minimum and hence improving the throughput, specifically in high-traffic situations. WebSockets are now tried as first transport. When a WebSocket connection is available, the client reports the status of “CONNECTED:WS-STREAMING”. The client reverts automatically to HTTP streaming in case it is not available.
The API allows subscribing to real-time data pushed by the server and to send any message to the server. The library offers automatic recovery from connection failures, automatic selection of the best available transport, and full decoupling of subscription and connection operations. The subscriptions are always meant as subscriptions “to the LightstreamerClient”, not “to the Server”; the LightstreamerClient is responsible for forwarding the subscriptions to the Server and re-forwarding all the subscriptions whenever the connection is broken and then reopened.
Finally, the new library also introduces automatic management of the second level for COMMAND mode subscriptions.
Before starting a brief overview of the use of the library with snippets of code showing the main features (yes, don’t worry, there is also the new version of our well-known Stock-List Demo rewritten with the new APIs), please consider these as basic reference points:
- Public API documentation: https://www.lightstreamer.com/api/ls-dotnetstandard-client/latest/
- The package of the library is available from NuGet: https://www.nuget.org/packages/Lightstreamer.DotNetStandard.Client/
- The complete sources of the library: https://github.com/Lightstreamer/Lightstreamer-lib-client-dotne
Let’s Quickstart with the Code
To connect to a Lightstreamer Server, a LightstreamerClient object has to be created, configured, and instructed to connect to a specified endpoint. A minimal version of the code that creates a LightstreamerClient and connects to the Lightstreamer Server on https://push.lightstreamer.com will look like this:
LightstreamerClient client = new LightstreamerClient("https://push.lightstreamer.com/", "DEMO");
client.connect();
In order to receive real-time updates from the Lightstreamer server the client needs to subscribe to specific Items handled by a Data Adapter deployed at the server-side. This can be accomplished by instantiating an object of type Subscription. For more details about Subscription in Lightstreamer see section 3.2 of the Lightstreamer General Concepts documentation. An example of subscription to three Items of the classic Stock-List example is:
Subscription s_stocks = new Subscription("MERGE");
s_stocks.Fields = new string[3] { "last_price", "time", "stock_name" };
s_stocks.Items = new string[3] { "item1", "item2", "item16" };
s_stocks.DataAdapter = "QUOTE_ADAPTER";
s_stocks.RequestedMaxFrequency = "3.0";
s_stocks.addListener(new QuoteListener());
client.subscribe(s_stocks);
Before sending the subscription to the server, usually, at least one SubscriptionListener is attached to the Subscription instance in order to consume the real-time updates. The following code shows in the console the value of changed fields each time a new update is received for the Items subscribed:
class QuoteListener : SubscriptionListener
{
void SubscriptionListener.onClearSnapshot(string itemName, int itemPos)
{
Console.WriteLine("Clear Snapshot for " + itemName + ".");
}
void SubscriptionListener.onCommandSecondLevelItemLostUpdates(int lostUpdates, string key)
{
Console.WriteLine("Lost Updates for " + key + " (" + lostUpdates + ").");
}
void SubscriptionListener.onCommandSecondLevelSubscriptionError(int code, string message, string key)
{
Console.WriteLine("Subscription Error for " + key + ": " + message);
}
void SubscriptionListener.onEndOfSnapshot(string itemName, int itemPos)
{
Console.WriteLine("End of Snapshot for " + itemName + ".");
}
void SubscriptionListener.onItemLostUpdates(string itemName, int itemPos, int lostUpdates)
{
Console.WriteLine("Lost Updates for " + itemName + " (" + lostUpdates + ").");
}
void SubscriptionListener.onItemUpdate(ItemUpdate itemUpdate)
{
Console.WriteLine("New update for " + itemUpdate.ItemName);
IDictionary listc = itemUpdate.ChangedFields;
foreach (string value in listc.Values)
{
Console.WriteLine(" >>>>>>>>>>>>> " + value);
}
}
void SubscriptionListener.onListenEnd(Subscription subscription)
{
// throw new System.NotImplementedException();
}
void SubscriptionListener.onListenStart(Subscription subscription)
{
// throw new System.NotImplementedException();
}
void SubscriptionListener.onRealMaxFrequency(string frequency)
{
Console.WriteLine("Real frequency: " + frequency + ".");
}
void SubscriptionListener.onSubscription()
{
Console.WriteLine("Start subscription.");
}
void SubscriptionListener.onSubscriptionError(int code, string message)
{
Console.WriteLine("Subscription error: " + message);
}
void SubscriptionListener.onUnsubscription()
{
Console.WriteLine("Stop subscription.");
}
}
Otherwise, to send messages in the opposite direction, i.e. from client to server, you only need a single line of code:
string msg = Console.ReadLine();
client.sendMessage("CHAT|"+msg);
This is an example of “fire and forget” pattern, but if the client needs more complex strategies to guarantee the ordering and get feedback from the server then it is possible to implement a ClientMessageListener and leverage all the sendmessage features. The message is dispatched by Lightstreamer server to the Metadata Adapter with the indication of the client session sender; the text is left to the free interpretation of the custom implementation of the adapter.
The well-know Stock-List Demo with .NET API 5.0.0
All the demos of the Microsoft .NET family have been updated with the new APIs, and in particular, I would like to focus on the Stock-List Demo that with the occasion has received a graphic restyling and some enrichment of features. The full source code of the demo can be retrieved from GitHub (https://github.com/Lightstreamer/Lightstreamer-example-StockList-client-dotnet).
The main body of the demo is occupied by a DataGridview which shows the information of the 30 Items all subscribed with a single subscription request. The application code implements a cell highlighting mechanism to highlight cells with a recently updated value.
To propagate any new updates to the market data of a stock from the Lightstrramer Client Library to the DataGridview we use the BeginInvoke to queue update process to the form thread.
void SubscriptionListener.onItemUpdate(ItemUpdate itemUpdate)
{
slClient.UpdateReceived(phase, itemUpdate.ItemPos, itemUpdate);
}
...
public void UpdateReceived(int ph, int itemPos, ItemUpdate update)
{
if (ph != this.phase)
return;
demoForm.BeginInvoke(updateDelegate, new Object[] { itemPos, update });
}
At the top right of the form, some controls have been added to manage the client session with the Lightstreamer server and the subscription to the Items displayed in the DataGridview, which allow you to:
- dynamically change the transport over which the client session with the Lightstremer server is based;
- reset the connection with the Lightstreamer server to force a new client session;
- dynamically change the max update frequency allowed for the Items subscribed; varying from unlimited to 1 update every 100 seconds.
Double-clicking on the last column a new Form will be shown with a Chart object from System.Windows.Forms drawing a real-time series for the quotes of the related stock. Each new Chart form involves a new Subscription in order to be totally released from any limitation on the frequency of updates imposed on the main subscription of the grid.
Conclusions
And now you can go deeper with the .NET Client Library and explore other Demo Examples. The .Net Client library can be available depending on Edition and License Type. To know what features are enabled by your license, please see the License tab of the Monitoring Dashboard (by default, available at /dashboard).