.NET Core Clients

The Nabto Edge .NET Core Client SDK is supported on Linux (x86_64), Windows (x86_64) and macOS (universal).

To use the library, checkout the github repository and add a reference to this from your project:

dotnet new console -n MyDemo
cd MyDemo
dotnet add reference path/to/src/NabtoClient
dotnet add package Microsoft.Extensions.Logging.Console

You can then use the library from your C# application as follows:

using Nabto.Edge.Client;
using Microsoft.Extensions.Logging;
using Dahomey.Cbor;

public class BasicConnectExample 
{

    public static async Task SayHello()
    {
        using (var client = INabtoClient.Create()) {
            using var loggerFactory = LoggerFactory.Create (builder => builder.AddConsole());
            var logger = loggerFactory.CreateLogger<INabtoClient>();
            client.SetLogger(logger);
            await using (var connection = await Connect(client)) {
                var coap = connection.CreateCoapRequest("GET", "/hello-world");
                var response = await coap.ExecuteAsync();
                var status = response.GetResponseStatusCode();
                Console.WriteLine($"Device replied with status {status}");
            }
        }
    }

    static async Task<IConnection> Connect(INabtoClient client)
    {
        var options = new ConnectionOptions
        {
            ProductId = "pr-fatqcwj9",
            DeviceId = "de-avmqjaje",
            PrivateKey = client.CreatePrivateKey(),
            ServerConnectToken = "demosct"
        };
        var connection = client.CreateConnection();
        connection.SetOptions(options);
        try {
            await connection.ConnectAsync();
        } catch (Exception e) {
            var localError = connection.GetLocalChannelErrorCode();
            var remoteError = connection.GetRemoteChannelErrorCode();
            Console.WriteLine($"Could not connect to device, reason: {e.Message}");
            Console.WriteLine($"     local channel error: {localError} ({NabtoClientError.GetErrorMessage(localError)})");
            Console.WriteLine($"     remote channel error: {remoteError} ({NabtoClientError.GetErrorMessage(remoteError)})");
            throw;
        }
        return connection;
    }
}

See the api documentation for details.

Handling Unmanaged Resources

The Nabto Edge .NET SDK wraps the underlying native Nabto Edge Client SDK. This means that all resources allocated are unmanaged from the .NET runtime’s perspective.

To handle release of Nabto Edge resources in a predictable and efficient manner, all Nabto Edge .NET C# classes that wrap a native resource, implement the IDisposable and IAsyncDisposable interfaces.

This means that you should use the using C# construct that ensures resources are automatically disposed of immediately when no longer referenced - instead of waiting for the runtime’s garbage collection.

For example, see the following snippet:

public static async Task SayHello()
    {
        using (var client = NabtoClient.Create()) {
            using var loggerFactory = LoggerFactory.Create (builder => builder.AddConsole());
            var logger = loggerFactory.CreateLogger<NabtoClient>();
            client.SetLogger(logger);
            await using (var connection = await Connect(client)) {
                var coap = connection.CreateCoapRequest("GET", "/hello-world");
                var response = await coap.ExecuteAsync();
                var status = response.GetResponseStatusCode();
                Console.WriteLine($"Device replied with status {status}");
            }
        }
    }

When the using (var foo = ...) { } block reaches the closing brace, Dispose() is automatically invoked on foo. Or DisposeAsync() if using the await using construct. A shorthand version without braces is also supported in newer C# versions where the object is disposed of at the end of the scope where it was allocated.

If you keep a reference to such a disposable object as a member variable in a class instead of using it in a simple scope as above, you must explicitly invoke Dispose() when cleaning up in your own class. For instance, by implementing IDisposable yourself; never defer such invocation to the finalizer (destructor) implementation as this means Nabto Edge resources are kept alive for an unpredictable long time. Avoiding the latter situation was the whole purpose of the wrapper implementing IDisposable in the first place.