Ably.PubSub.Core 2.0.0

Prefix Reserved
dotnet add package Ably.PubSub.Core --version 2.0.0
                    
NuGet\Install-Package Ably.PubSub.Core -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Ably.PubSub.Core" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ably.PubSub.Core" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Ably.PubSub.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Ably.PubSub.Core --version 2.0.0
                    
#r "nuget: Ably.PubSub.Core, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Ably.PubSub.Core@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Ably.PubSub.Core&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Ably.PubSub.Core&version=2.0.0
                    
Install as a Cake Tool

Ably Pub/Sub .NET Header

NuGet: Ably.PubSub.Server NuGet: Ably.PubSub.Device License

Ably Pub/Sub .NET SDK

The .NET SDK for Ably Pub/Sub: publish and subscribe to channels, and use message history and presence, from servers and from applications on end-user devices.

Overview

The SDK is published as two packages, one for each side of the connection. You choose the package by where your code runs, and create your client through that package's entry point.

Package Use it for Entry point Platforms
Ably.PubSub.Server Servers and other trusted backend environments PubSubServer.CreateRealtimeClient, PubSubServer.CreateHttpClient .NET, .NET Framework, Mono
Ably.PubSub.Device Applications on end-user devices PubSubDevice.CreateClient .NET, .NET Framework, Mono, .NET for Android and iOS, MAUI, Unity

Choosing a package

Your code runs in Package Create clients with
An ASP.NET Core app, a worker service, an Azure host, a console job or any other backend you operate Ably.PubSub.Server PubSubServer.CreateRealtimeClient(...) or PubSubServer.CreateHttpClient(...)
A desktop app (WPF, WinForms), a MAUI or .NET for Android/iOS app, a Unity game, or any other client the end user holds Ably.PubSub.Device PubSubDevice.CreateClient(...)

Choose by where the code runs, not by which Ably features you use: both packages expose the whole Ably.PubSub API. The device package has a single entry point; for HTTP-only calls on a device, use the client's HttpClient property, as shown in the device quick start below.

Requirements

Platform Requirement
.NET .NET 6.0 or later. Both packages ship net6.0 and net7.0 builds; later .NET versions use the net7.0 build.
.NET Framework 4.6.2 or later, or Mono.
.NET for Android, .NET for iOS, MAUI With Ably.PubSub.Device. See "MAUI and assembly trimming" under Platform notes.
Xamarin and other .NET Standard 2.0 runtimes Through the netstandard2.0 build of either package.
Unity 2019.x or later, with the API Compatibility Level set to .NET Standard 2.0. See "Unity" under Platform notes.

Installation

Use exactly one of Ably.PubSub.Server or Ably.PubSub.Device in an app. Never reference Ably.PubSub.Core directly: it is the shared implementation, and both packages bring in the matching version for you.

Server

dotnet add package Ably.PubSub.Server

Or add a package reference to your project file:

<PackageReference Include="Ably.PubSub.Server" Version="2.0.0" />

Device

dotnet add package Ably.PubSub.Device

Or add a package reference to your project file:

<PackageReference Include="Ably.PubSub.Device" Version="2.0.0" />

Unity

Unity projects install the .unitypackage attached to each GitHub release instead of a NuGet package. See "Unity" under Platform notes.

Migrating from 1.x

Version 2 replaces the ably.io package with these two packages and moves the root namespace from IO.Ably to Ably.PubSub. Remove ably.io, add the package for your side, change each using IO.Ably...; to using Ably.PubSub...; (IO.Ably.Rest becomes Ably.PubSub.Http), and replace new AblyRealtime(...) and new AblyRest(...) with the entry points above. They return PubSubRealtimeClient and PubSubHttpClient.

dotnet remove package ably.io
dotnet add package Ably.PubSub.Server   # or Ably.PubSub.Device

Other changes that can affect a running app: Endpoint replaces Environment, RestHost and RealtimeHost, publish methods return a PublishResult, releasing a channel that isn't detached throws, and device push-receive is not available. See UPDATING.md for the full list.

Quick start

Server

Use an API key on a server. The following program connects, subscribes to a channel, publishes a message to it and waits for the message to arrive.

using System;
using System.Threading.Tasks;
using Ably.PubSub;
using Ably.PubSub.Realtime;
using Ably.PubSub.Server;

PubSubRealtimeClient realtime = PubSubServer.CreateRealtimeClient("xxxxxx.yyyyyy:zzzzzzzz");

realtime.Connection.On(ConnectionEvent.Connected, _ => Console.WriteLine("Connected to Ably"));

// Subscribing attaches the channel. Publishing while the client is still
// connecting queues the message until the connection is established.
IRealtimeChannel channel = realtime.Channels.Get("test-channel");
var received = new TaskCompletionSource<Message>();
channel.Subscribe(msg => received.TrySetResult(msg));

Result<PublishResult> result = await channel.PublishAsync("test-event", "hello world");
if (result.IsFailure)
{
    Console.WriteLine($"Publish failed: {result.Error}");
    return;
}

Message message = await received.Task;
Console.WriteLine($"Received: {message.Data}");

realtime.Close();

To publish and read history over HTTP without a realtime connection, create an HTTP client instead. Publishing returns a PublishResult with the serial of each message:

using System;
using Ably.PubSub;
using Ably.PubSub.Http;
using Ably.PubSub.Server;

PubSubHttpClient http = PubSubServer.CreateHttpClient("xxxxxx.yyyyyy:zzzzzzzz");
IHttpChannel channel = http.Channels.Get("test-channel");

PublishResult published = await channel.PublishAsync("test-event", "hello world");
Console.WriteLine($"Published, serials: {string.Join(", ", published.Serials)}");

PaginatedResult<Message> history = await channel.HistoryAsync();
foreach (Message message in history.Items)
{
    Console.WriteLine($"{message.Name}: {message.Data}");
}

Your server also issues the tokens that devices authenticate with. Return a token request from the endpoint your devices use as their AuthUrl:

using System;
using Ably.PubSub;
using Ably.PubSub.Server;

PubSubHttpClient http = PubSubServer.CreateHttpClient("xxxxxx.yyyyyy:zzzzzzzz");

// Authenticate the caller first, then issue a token request for that user only,
// granting only the operations the user needs.
var capability = new Capability("{\"test-channel\":[\"publish\",\"subscribe\",\"history\"]}");

string tokenRequest = await http.Auth.CreateTokenRequestAsync(new TokenParams
{
    ClientId = "me", // the authenticated user's ID
    Capability = capability, // without it, the token gets all of the API key's capabilities
});

// Return this JSON unchanged, with the content type application/json. A text/plain
// response is treated as a token string.
Console.WriteLine(tokenRequest);

In an ASP.NET Core minimal API, for example, return it with Results.Content(tokenRequest, "application/json"). To work with it as a TokenRequest object, use JsonHelper.Deserialize<TokenRequest>(tokenRequest). See token authentication for how devices use it.

Important: clients from PubSubServer declare themselves as servers. Authenticate them with an API key. Token authentication works only with a token that carries the signed x-ably-clientType=server claim (a JWT); with any other token, Ably rejects the connection or request with error 40167. Clients from PubSubDevice are not affected. See Server clients and token authentication.

Device

Authenticate a device with tokens issued by your own server, through AuthUrl or AuthCallback. Never embed an API key in an app that runs on an end-user device.

using System;
using System.Threading.Tasks;
using Ably.PubSub;
using Ably.PubSub.Device;
using Ably.PubSub.Realtime;

PubSubRealtimeClient realtime = PubSubDevice.CreateClient(options =>
{
    options.AuthUrl = new Uri("https://your-server.example.com/ably-auth");
    options.ClientId = "me";
});

// The client connects automatically. Subscribing attaches the channel.
IRealtimeChannel channel = realtime.Channels.Get("test-channel");
var received = new TaskCompletionSource<Message>();
channel.Subscribe(msg => received.TrySetResult(msg));

Result<PublishResult> result = await channel.PublishAsync("test-event", "hello world");
if (result.IsFailure)
{
    Console.WriteLine($"Publish failed: {result.Error}");
    return;
}

Message message = await received.Task;
Console.WriteLine($"Received: {message.Data}");

realtime.Close();

To get tokens from your own code instead of a URL, set AuthCallback. It can return a token string, a TokenDetails, or a token request, including the serialized request from Auth.CreateTokenRequestAsync:

PubSubRealtimeClient realtime = PubSubDevice.CreateClient(options =>
{
    options.AuthCallback = async tokenParams =>
    {
        // Ask your server for a token request, token details or token string.
        return await RequestTokenFromYourServerAsync(tokenParams); // your function
    };
    options.ClientId = "me";
});

The device package has no separate HTTP entry point. For HTTP calls only, create the client without connecting and use its HttpClient:

using System;
using Ably.PubSub;
using Ably.PubSub.Device;

PubSubRealtimeClient client = PubSubDevice.CreateClient(options =>
{
    options.AuthUrl = new Uri("https://your-server.example.com/ably-auth");
    options.AutoConnect = false; // HTTP calls only; call client.Connect() to go realtime
});

PaginatedResult<Message> history = await client.HttpClient.Channels.Get("test-channel").HistoryAsync();
foreach (Message message in history.Items)
{
    Console.WriteLine($"{message.Name}: {message.Data}");
}

Common configuration

Every entry point accepts an API key, a ClientOptions object, or an Action<ClientOptions> that configures one.

Endpoint

Endpoint selects the Ably host for both HTTP requests and the realtime connection. It replaces the 1.x Environment, RestHost and RealtimeHost options.

PubSubRealtimeClient realtime = PubSubServer.CreateRealtimeClient(options =>
{
    options.Key = "xxxxxx.yyyyyy:zzzzzzzz";
    options.Endpoint = "nonprod:sandbox";
});

Never put a port in Endpoint: localhost:8080 is not a hostname and does not resolve. Set the port with TlsPort instead, or with Port when TLS is off (Tls = false, which needs token authentication). See Choose the host with Endpoint for how each value resolves.

Proxy

The SDK uses your runtime's default proxy settings, for both HTTP requests and the realtime connection. On .NET, these are HttpClient.DefaultProxy, which comes from the HTTPS_PROXY and HTTP_PROXY environment variables or from the system proxy settings. On .NET Framework, they come from the system proxy settings and your app's configuration.

To set a proxy in code, pass your own HttpClient. It applies to HTTP requests only; the realtime connection still uses the default proxy settings.

using System.Net;
using System.Net.Http;
using Ably.PubSub;
using Ably.PubSub.Server;

var handler = new HttpClientHandler
{
    Proxy = new WebProxy("http://proxy.example.com:8080"),
    UseProxy = true,
};

PubSubHttpClient http = PubSubServer.CreateHttpClient(options =>
{
    options.Key = "xxxxxx.yyyyyy:zzzzzzzz";
    options.HttpClient = new HttpClient(handler);
});

If the proxy needs authentication, set WebProxy.Credentials.

Logging

LogLevel sets what the SDK logs: LogLevel.Debug (the most verbose), Warning (the default), Error or None. The SDK writes log lines to the ILoggerSink you set as LogHandler; without one, log lines aren't written anywhere. This works the same way as in 1.x.

using System;
using Ably.PubSub;
using Ably.PubSub.Server;

PubSubRealtimeClient realtime = PubSubServer.CreateRealtimeClient(options =>
{
    options.Key = "xxxxxx.yyyyyy:zzzzzzzz";
    options.LogLevel = LogLevel.Debug;
    options.LogHandler = new ConsoleLogSink();
});

class ConsoleLogSink : ILoggerSink
{
    public void LogEvent(LogLevel level, string message)
    {
        Console.WriteLine($"[{level}] {message}");
    }
}

All clients in a process share one logger. Each client you create applies its LogLevel, and its LogHandler if set, to that shared logger, so give every client the same logging options.

Platform notes

Unity

Download ably.pubsub.<version>.unitypackage from the latest GitHub release and import it with Assets > Import Package > Custom Package. The package bundles Ably.PubSub.Device, so create clients with PubSubDevice.CreateClient(...). Set ClientOptions.CustomContext to run callbacks on the main thread. WebGL builds are not supported. See the Unity README.

MAUI and assembly trimming

The SDK uses reflection. In a MAUI or trimmed app, keep the Ably assembly from being trimmed by adding this to your .csproj:

<ItemGroup>
  <TrimmerRootAssembly Include="Ably.PubSub.Core" />
</ItemGroup>

.NET Framework

Both packages run on .NET Framework 4.6.2 or later. For high-throughput use on .NET Framework, for example messages larger than 50 KB, set the WebSocket send and receive buffers to the 64 KB maximum:

using Ably.PubSub;
using Ably.PubSub.Server;
using Ably.PubSub.Transport;

var maxBufferSize = 64 * 1024;

var options = new ClientOptions("xxxxxx.yyyyyy:zzzzzzzz")
{
    TransportFactory = new MsWebSocketTransport.TransportFactory(new MsWebSocketOptions
    {
        SendBufferInBytes = maxBufferSize,
        ReceiveBufferInBytes = maxBufferSize,
    }),
};

PubSubRealtimeClient realtime = PubSubServer.CreateRealtimeClient(options);

In a device app, set the same TransportFactory on the ClientOptions you pass to PubSubDevice.CreateClient.

Known limitations

  • Device push-receive (activating a device for push notifications on Android or iOS) is not available in 2.0. The API stays public: Push.Activate() and Push.Deactivate() throw an AblyException, and the client's Device and a channel's Push are null. To request the feature, comment on https://github.com/ably/ably-pubsub-dotnet/issues/1360. See Push notifications.
  • Push administration (Push.Admin) is available on clients from both Ably.PubSub.Device and Ably.PubSub.Server. It is intended for server-side use and needs the push-admin capability, so use it from a backend built on Ably.PubSub.Server.
  • Unity WebGL builds are not supported (https://github.com/ably/ably-pubsub-dotnet/issues/1211).

Further reading

Contributing

Read CONTRIBUTING.md before contributing; it also describes the release process. The build uses Cake: run ./build.sh --target=Build.NetStandard (or build.cmd on Windows) to build and lint before you push.

Support, feedback and troubleshooting

For help, visit Ably's support page. Report bugs and compatibility problems on GitHub Issues.

License

Licensed under the Apache License, Version 2.0. See LICENSE.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net46 is compatible.  net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Ably.PubSub.Core:

Package Downloads
Ably.PubSub.Device

The supported entry point for Ably Pub/Sub in an end-user device application - a mobile or desktop app, a Unity game, a set-top box or any other client the end user holds. Create clients through PubSubDevice.CreateClient(...) in the Ably.PubSub.Device namespace; it accepts an API key, an Ably token, a ClientOptions or an Action<ClientOptions>, and returns the ordinary PubSubRealtimeClient so the whole of the Ably.PubSub API remains available, including device-side connectionless operations such as message history, presence reads and token requests. Creating a client any other way - including directly from the Ably.PubSub.Core implementation package this depends on - does not classify it as device-side, which Ably's platform behaviour and billing depend on. Install Ably.PubSub.Server instead in a server-side application. See https://www.ably.com for more info.

Ably.PubSub.Server

The supported entry point for Ably Pub/Sub in a server-side application - an ASP.NET or Azure host, a worker, a console app or any other backend the end user does not hold. Create clients through PubSubServer.CreateRealtimeClient(...) and PubSubServer.CreateHttpClient(...) in the Ably.PubSub.Server namespace; each accepts an API key, a ClientOptions or an Action<ClientOptions>, and returns the ordinary PubSubRealtimeClient or PubSubHttpClient so the whole of the Ably.PubSub API remains available. Server clients authenticate with an API key, or with a JWT that carries the signed server claim; Ably rejects any other token with error 40167. Creating a client any other way - including directly from the Ably.PubSub.Core implementation package this depends on - does not classify it as server-side, which Ably's platform behaviour and billing depend on. Install Ably.PubSub.Device instead in an end-user device application. See https://www.ably.com for more info.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 65 11/3/2026