Skip to content
.NET, Xamarin and Mono client library SDK for Ably realtime messaging service
Branch: master
Clone or download
Pull request Compare This branch is 72 commits behind ably:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
common @ d0df9ca


NuGet version

A .NET client library for, the realtime messaging service. This library currently targets the Ably 1.1-beta client library specification. You can jump to the 'Known Limitations' section to see the features this client library does not yet support or or view our client library SDKs feature support matrix to see the list of all the available features.

Supported platforms

* To target Windows 7 (with .Net 4.6) a custom ITransportFactory will need to be implemented in your project that uses an alternate Web Socket library. This is because System.Net.WebSockets is not fully implementented on Windows 7. See this repository for a working example using the websocket4net library.

** We regression-test the library against .NET Core 2 but it is designed to be compatible with all versions of .NET Core (and any other runtime implementation that is compatible with .NET Standard 1.4 or greater). If you find any compatibility issues, please do raise an issue in this repository or contact Ably customer support for advice. Any known runtime incompatibilities can be found here.

Partial platform support

The following platforms are supported, but have some shortcomings or considerations:


Unity support is currently in beta. See below for details on why it's considered beta.

Shortcomings & considerations:

  • This library is only tested manually on Unity. We do not yet have automated tests running on the Unity platform.
  • Installation requires developers to manually set up the library

Unity Requirements:

  • Unity 2018.2.0 or newer
  • The following Unity Player settings must be applied:
    • Scripting Runtime Version should be '.NET 4.x Equivelant'
    • Api Compatibility Level should be '.NET Standard 2.0'
  • Json.NET 9.0.1 or newer. If you are targetting macOS or iOS (or other platforms that require the IL2CPP scripting backend) then a version of Json.NET that has been modified to work with an AOT compiler is required, we have had success with Json.Net.Unity3D

The .NET Standard build of ably-dotnet (IO.Ably.dll) needs to be added the asset folder of your Unity project. As Unity does not support Nuget out of the box we currently recommend building ably-dotnet from source, although it should be possible to extract the required assembly from the nuget package or use a 3rd party Nuget extension for Unity, but those options are beyond the scope of this document. To build from source clone this repository and build the IO.Ably.NETStandard20 project, this can be done from Visual Studio by opening the IO.Ably.sln file or via the command line. To build via the comandline cd to ably-dotnet/src/IO.Ably.NETStandard20/ and run dotnet build, the build output can then be found in ably-dotnet/src/IO.Ably.NETStandard20/bin/Release/netstandard2.0, navigate there to obtain the required IO.Ably.dll. Finally, install a compatible version of Json.NET into your Unity projects asset folder (e.g. Json.Net.Unity3D).

Unsupported platforms

A portable class library (PCL) version is not available. See this comment for more information on this choice and the potential workarounds that are available.

Known Limitations

This client library is currently not compatible with some of the Ably features:

Push Notification target
Push Notification admin
Custom transportParams
Message extras


Visit for a complete API reference and more examples.


The client library is available as a nuget package.

You can install it from the Package Manager Console using this command

PM> Install-Package

Using the Realtime API


All examples assume a client has been created as follows:

// using basic auth with API key
var realtime = new AblyRealtime("<api key>");
// using taken auth with token string
var realtime = new AblyRealtime(new ClientOptions { Token = "token" });

If you do not have an API key, sign up for a free API key now


Connecting and observing connection state changes. By default the library automatically initialises a connection.

realtime.Connection.On(ConnectionState.Connected, args =>
    //Do stuff  

To disable the default automatic connect behaviour of the library, set AutoConnect=false when initialising the client.

var realtime = new AblyRealtime(new ClientOptions("<api key>") {AutoConnect = false});
// some code

Subscribing to connection state changes and observing errors:

realtime.Connection.On(args =>
    var currentState = args.Current; //Current state the connection transitioned to
    var previousState = args.Previous; // Previous state
    var error = args.Reason; // If the connection errored the Reason object will be populated.

Subscribing to a channel

Create a channel

var channel = realtime.Channels.Get("test");

Subscribing to all events:

channel.Subscribe(message =>
    var name = message.Name;
    var data = message.Data;

Subscribing to specific events:

channel.Subscribe("myEvent", message =>
    var name = message.Name;
    var data = message.Data;

Observing channel state changes and errors:

channel.On(args =>
    var state = args.NewState; //Current channel State
    var error = args.Error; // If the channel errored it will be refrected here


channel.On(ChannelState.Attached, args =>
    // Do stuff when channel is attached

Publishing to a channel

The client support a callback and async publishing. The simplest way to publish is:

channel.Publish("greeting", "Hello World!");

with a callback:

channel.Publish("greeting", "Hello World!", (success, error) =>
    //if publish succeeded `success` is true
    //if publish failed `success` is false and error will contain the specific error

and the async version which if you await it will complete when the message has been acknowledged or rejected by the Ably service:

var result = await channel.PublishAsync("greeting", "Hello World!");
//You can check if the message failed
if (result.IsFailure)
    var error = result.Error; // The error reason can be accessed as well

Getting channel history

Calling history returns a paginated list of message. The object is of type PaginatedResult<Message> and can be iterated through as a normal list.

var history = await channel.HistoryAsync();
//loop through current history page
foreach (var message in history.Items)
    //Do something with message
//Get next page.
var nextPage = await history.NextAsync();

Getting presence history

Getting presence history is similar to how message history works. You get back PaginatedResult<PresenceMessage> and can navigate or iterate through the page

var presenceHistory = await channel.Presence.HistoryAsync();
//loop through the presence messages
foreach (var presence in presenceHistory.Items)
    //Do something with the messages

var presenceNextPage = await presenceHistory.NextAsync();

Symmetric end-to-end encrypted payloads on a channel

When a 128 bit or 256 bit key is provided to the library, all payloads are encrypted and decrypted automatically using that key on the channel. The secret key is never transmitted to Ably and thus it is the developer's responsibility to distribute a secret key to both publishers and subscribers.

var secret = Crypto.GetRandomKey();
var encryptedChannel = realtime.Get("encrypted", new ChannelOptions(secret));
encryptedChannel.Subscribe(message =>
    var data =; // sensitive data (encrypted before published)
encryptedChannel.Publish("name (not encrypted)", "sensitive data (encrypted before published)");

Using the REST API


The rest client provides a fully async wrapper around the Ably service web api.

All examples assume a client and/or channel has been created as follows:

var client = new AblyRest("<api key>");
var channel = client.Channels.Get("test");

If you do not have an API key, sign up for a free API key now

Publishing a message to a channel

await channel.PublishAsync("name", "data");

If the publish is not successful an error will be thrown of type AblyException containing error codes and error description

    await channel.PublishAsync("name", "errorData");
catch(AblyException ablyError) 
    // Log error

Querying channel history

var historyPage = await channel.HistoryAsync();
foreach (var message in historyPage.Items)
    //Do something with each message
//get next page
var nextHistoryPage = await historyPage.NextAsync();

Current presence members on a channel

var presence = await channel.Presence.GetAsync();
var first = presence.Items.FirstOrDefault();
var clientId = first.clientId; //clientId of the first member present
var nextPresencePage = await presence.NextAsync();
foreach (var presenceMessage in nextPresencePage.Items)
    //do stuff with next page presence messages

Querying the presence history

// Presence history
var presenceHistory = await channel.Presence.HistoryAsync();
foreach (var presenceMessage in presenceHistory.Items)
    // Do stuff with presence messages

var nextPage = await presenceHistory.NextAsync();
foreach (var presenceMessage in nextPage.Items)
    // Do stuff with next page messages

Using the AuthCallback

A callback to obtain a signed TokenRequest string or a TokenDetails instance.

To use AuthCallback create a ClientOptions instance and assign an appropriate delegate to the AuthCallback property and pass the ClientOptions to a new AblyRealtime instance.

var options = new ClientOptions
    AuthCallback = async tokenParams =>
        // Return a TokenDetails instance or a preferably a TokenRequest string.
        // Typically this method would wrap a request to your web server.
        return await GetTokenDetailsOrTokenRequestStringFromYourServer();        
var client = new AblyRealtime(options);

Generate a TokenRequest

Token requests are issued by your servers and signed using your private API key. This is the preferred method of authentication as no secrets are ever shared, and the token request can be issued to trusted clients without communicating with Ably.

string tokenRequest = await client.Auth.CreateTokenRequestAsync();

Symmetric end-to-end encrypted payloads on a channel

When a 128 bit or 256 bit key is provided to the library, all payloads are encrypted and decrypted automatically using that key on the channel. The secret key is never transmitted to Ably and thus it is the developer's responsibility to distribute a secret key to both publishers and subscribers.

var secret = Crypto.GetRandomKey();
var encryptedChannel = client.Channels.Get("encryptedChannel", new ChannelOptions(secret));
await encryptedChannel.PublishAsync("name", "sensitive data"); //Data will be encrypted before publish
var history = await encryptedChannel.HistoryAsync();
var data = history.First().data; // "sensitive data" the message will be automatically decrypted once received

Fetching your application's stats

var stats = await client.StatsAsync();
var firstItem = stats.Items.First();
var nextStatsPage = await stats.NextAsync();

Fetching the Ably service time

DateTimeOffset time = await client.TimeAsync();


This library has dependencies that can differ depending on the target platform. See the nuget page for specifics.

Support, feedback and troubleshooting

Please visit for access to our knowledgebase and to ask for any assistance.

You can also view the community reported Github issues.


  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Ensure you have added suitable tests and the test suite is passing
  5. Push to the branch (git push origin my-new-feature)
  6. Create a new Pull Request

Building and Packaging

The build scripts are written in powershell using PSake and need to be run on Windows with Visual Studio 2017 installed. Additionally nuget.exe and GitVersion.exe are required, these can be installed via chocolatey

choco install nuget.commandline
choco install gitversion.portable

Running .\build.ps1 will start the build process and run the tests. Running package.ps1 will run the build script and create a nuget package.

Working from source

If you want to incorporate ably-dotnet into your project from source (perhaps to use a specific development branch) the simplest way to do so is to add references to the relevant ably-dotnet projects. The following steps are specific to Visual Studio 2017, but the pricipal should transfer to other IDEs

  1. Clone this repository to your local system
  2. Open the solution you want to reference ably-dotnet from
  3. In Solution Explorer right click the root note (it will be labled Solution 'YourSolutionName')
  4. Select Add > Existing Project from the context menu
  5. Browse to the ably-dotnet repository and add ably-dotnet\src\IO.Ably.Shared\IO.Ably.Shared.shproj
  6. Browse to the ably-dotnet repository and add the project that corresponds to your target platform, so if you are targetting .Net Framework (AKA Classic .Net) you would add ably-dotnet\src\IO.Ably.NETFramework\IO.Ably.NETFramework.csproj, if you are targeting .NET Core 2 then chose ably-dotnet\src\IO.Ably.NetStandard20\IO.Ably.NetStandard20.csproj and so on.
  7. In any project that you want to use ably-dotnet you need to add a project reference, to do so:
    1. Find your project in Solution Explorer and expand the tree so that the Dependencies node is visible
    2. Right click Dependencies and select Add Reference
    3. In the dialogue that opens you should see a list of the projects in your solution. Check the box next to IO.Ably.NETFramework (or whatever version you are trying to use) and click OK.

Release process

This library uses semantic versioning. For each release, the following needs to be done:

  • Update the version number in GitVersion.yml† and commit the change.
  • Run github_changelog_generator to automate the update of the CHANGELOG. Once the CHANGELOG update has completed, manually change the Unreleased heading and link with the current version number such as v1.0.0. Also ensure that the Full Changelog link points to the new version tag instead of the HEAD. Commit this change.
  • Add a tag for the version and push to origin such as git tag 1.0.0 && git push origin 1.0.0. For beta versions the version string should be Maj.Min.Patch-betaN, e.g 1.0.0-beta1
  • Visit and Add release notes for the release including links to the changelog entry.
  • Run package.ps1 to create the nuget package.
  • Run nuget push*.nupkg -Source (a private nuget API Key is required to complete this step, more information on publishing nuget packages can be found here)

† GitVersion is required, see the preceeding section 'Building and Packaging' for more information.


Copyright (c) 2016 Ably Real-time Ltd, Licensed under the Apache License, Version 2.0. Refer to LICENSE for the license terms.

You can’t perform that action at this time.