CoAP.NET is a modernized CoAP framework for .NET 10. It keeps the original CoAP.NET client and server model, blockwise transfer, observe support, and resource tree, while adding Microsoft.Extensions.Logging integration, Native AOT analyzer compatibility, Resource/MVC-style hosting, and optional DTLS PSK transport.
See ROADMAP.md for the CoAP route adapter and low-allocation plan. The Resource/MVC sample and migration guide are available in CoAP.Example/CoAP.ResourceMvc and docs/resource-mvc-migration.md. C12 release validation is tracked in docs/c12-release-checklist.md. The 3.0 release notes are available in docs/release-notes/3.0.0.md.
| Package | Purpose | Install |
|---|---|---|
| IoTSharp.CoAP.NET | Core CoAP client/server, resource tree, blockwise, Observe, DTLS PSK, Generic Host integration, Resource/MVC routing. | dotnet add package IoTSharp.CoAP.NET --version 3.0.0 |
| IoTSharp.CoAP.NET.SourceGeneration | Analyzer package that emits generated Resource/MVC endpoint factories for trim/AOT-friendly hosts. | dotnet add package IoTSharp.CoAP.NET.SourceGeneration --version 3.0.0 |
| IoTSharp.CoAP.NET.AspNetCore | ASP.NET Core IApplicationBuilder adapter for hosts that want app.MapCoapResources(). |
dotnet add package IoTSharp.CoAP.NET.AspNetCore --version 3.0.0 |
- CoAP client APIs for GET, POST, PUT, DELETE, discovery, Observe, synchronous calls, and asynchronous calls.
- CoAP server APIs with the original resource tree,
.well-known/corediscovery, blockwise transfer, Observe, and resource attributes. - UDP
coap://transport and optional PSK-based DTLScoaps://transport. - Host-managed startup through
AddCoapServer(),AddCoapResources(),AddCoapMvc(), andMapCoapResources(). - Resource/MVC-style programming with
[CoapResource],[CoapRoute],[CoapGet],[CoapPost],[CoapPut],[CoapDelete], and[CoapObserve]. - Endpoint metadata for method, path, Content-Format, Accept, Observe, resource discovery attributes, and authorization policy names.
- Parameter binding for route values, query options, request options, payloads,
CancellationToken,CoapRouteContext, and remote endpoint values. - JSON payload binding through source-generated
System.Text.Jsonmetadata or explicit reflection-based compatibility. - Endpoint filters, authorization hooks, and request context hooks for host-owned identity, tenant, audit, and policy integration.
- Low-allocation route context surfaces, including
ReadOnlyMemory<byte>payload access and compact route value storage. Microsoft.Extensions.Loggingintegration and Native AOT analyzer coverage for the core package.
Create a Generic Host server:
using CoAP;
using CoAP.Server.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddCoapServer(options =>
{
options.ListenAnyIP(5683);
});
builder.Services.AddCoapSystemTextJsonPayloadBinder();
builder.Services.AddCoapResources();
var app = builder.Build();
app.MapCoapResources();
await app.RunAsync();Declare a resource action:
using CoAP;
using CoAP.Server.Routing;
[CoapResource]
[CoapRoute("sensors/{sensor}")]
public sealed class SensorCoapResource : CoapResourceBase
{
[CoapPost("readings")]
[CoapConsumes(MediaType.ApplicationJson)]
[CoapProduces(MediaType.ApplicationJson)]
public CoapRouteResult UploadReading(
string sensor,
[CoapFromQuery] int point,
ReadingPayload payload)
{
return CoapRouteResult.Json("{\"ok\":true}");
}
}
public sealed class ReadingPayload
{
public double Value { get; set; }
}Use source-generated endpoint factories and JSON metadata in AOT-sensitive hosts:
builder.Services.AddCoapJsonPayloadBinder(MyCoapJsonContext.Default);
builder.Services.AddCoapResources(options =>
{
options.AddEndpointFactory(MyGeneratedCoapEndpoints.Create);
});Send a client request:
using CoAP;
var client = new CoapClient(new Uri("coap://127.0.0.1:5683/sensors/demo/readings?point=1"));
var response = client.Post("{\"value\":42}", MediaType.ApplicationJson);Resource, IResource, ResourceAttributes, DiscoveryResource, resource
tree, and .well-known/core remain CoAP/CoRE protocol concepts inside
CoAP.NET. They are not host application domain objects. Existing Resource-style
applications can continue to add resources to CoapServer, while newer host
integration should use Resource-oriented hosting APIs such as
AddCoapServer(), AddCoapResources(), and MapCoapResources().
The current compatibility entry points are:
AddCoapServer(),AddCoapResources()/AddCoapMvc(), andMapCoapResources()for host-managed server lifetime and resource endpoint mapping.CoAP.Server.CoapServerfor server lifetime, endpoint registration, and the root resource tree.CoAP.Server.Resources.Resource/IResourcefor protocol resources, method handlers, attributes, observe, and discovery.CoAP.CoapClientandCoAP.Requestfor synchronous and asynchronous client requests, observe, and discovery.CoAP.Channel.DtlsPskChannelandDtlsPskClientChannelfor optional DTLS PSK transport.CoAP.Server.Routing.CoapRouteEndpointfor low-level route handler compatibility. It is useful for tests and adapters, but it is not the recommended future host application API.
CoAP.NET no longer ships a custom CoAP.Log abstraction. Configure the shared
logger factory once during application startup:
using CoAP;
CoapLogging.LoggerFactory = loggerFactory;The default logger factory is NullLoggerFactory.Instance, so libraries can use
CoAP.NET without configuring logging.
using CoAP;
var client = new CoapClient(new Uri("coap://127.0.0.1:5683/db/demo/m/cpu?token=secret"))
{
Timeout = 5000,
};
Response response = client.Post("cpu,host=a value=1 1", MediaType.TextPlain);For DTLS PSK, create an explicit endpoint and assign it to the client:
using CoAP;
using CoAP.Channel;
using CoAP.Net;
var config = new CoapConfig();
using var endpoint = new CoAPEndPoint(
new DtlsPskClientChannel("device-1", "shared-secret"),
config);
endpoint.Start();
var client = new CoapClient(new Uri("coaps://127.0.0.1:5684/db/demo/m/cpu?token=secret"), config)
{
EndPoint = endpoint,
Timeout = 10000,
};
Response response = client.Post("cpu,host=a value=1 1", MediaType.TextPlain);Recommended host-managed startup:
builder.Services.AddCoapServer(options =>
{
options.ListenAnyIP(5683);
});
builder.Services.AddCoapResources();
var app = builder.Build();
app.MapCoapResources();
app.Run();Native AOT hosts should register generated endpoint factories and source-generated JSON metadata:
builder.Services.AddCoapJsonPayloadBinder(MyCoapJsonContext.Default);
builder.Services.AddCoapResources(options =>
{
options.AddEndpointFactory(MyGeneratedCoapEndpoints.Create);
});Add the source generator analyzer package to the host project so
MyGeneratedCoapEndpoints.Create(...) is emitted during compilation:
dotnet add package IoTSharp.CoAP.NET.SourceGeneration --version 3.0.0Reflection-based resource discovery remains available for non-AOT hosts or compatibility tests:
builder.Services.AddCoapResources(options =>
{
options.AddReflectionResourceDiscovery();
});Resource attribute routing:
using CoAP;
using CoAP.Server.Routing;
using System.Threading;
using System.Threading.Tasks;
[CoapResource]
[CoapRoute("sensors/{sensor}")]
public sealed class SensorCoapResource : CoapResourceBase
{
[CoapPost("readings")]
[CoapResourceTitle("Sensor reading upload")]
public ValueTask<CoapRouteResult> UploadReadingAsync(
string sensor,
CancellationToken cancellationToken)
{
var payload = Payload;
return new ValueTask<CoapRouteResult>(CoapRouteResult.Changed());
}
}Filters and host-owned security hooks:
using CoAP;
using CoAP.Server.Routing;
[CoapResource]
[CoapRoute("diagnostics/{target}")]
public sealed class DiagnosticsCoapResource
{
[CoapGet("status")]
[CoapAuthorize("diagnostics.read")]
public CoapRouteResult Status(CoapRouteContext context)
{
var tenant = (string)context.Items["tenant"];
return CoapRouteResult.Text(StatusCode.Content, tenant);
}
}Hosts register ICoapRequestContextHook, ICoapAuthorizationHook, and
ICoapEndpointFilter implementations in DI; they are resolved from the request
scope when available. CoAP.NET only defines metadata, ordering, and invocation
contracts; tenant isolation, identity checks, audit, and human confirmation
remain host application responsibilities.
Legacy Resource tree compatibility:
using CoAP.Server;
using CoAP.Server.Resources;
var server = new CoapServer();
server.Add(new HelloResource());
server.Start();
sealed class HelloResource : Resource
{
public HelloResource()
: base("hello")
{
}
protected override void DoGet(CoapExchange exchange)
{
exchange.Respond("Hello from CoAP.NET");
}
}The full Resource-style server sample is in
CoAP.Example/CoAP.Server. It registers resources such as hello, storage,
large, separate, and time by calling server.Add(new ...Resource(...)).
The full host-managed Resource/MVC sample is in
CoAP.Example/CoAP.ResourceMvc. It demonstrates AddCoapServer(),
AddCoapResources(), MapCoapResources(), JSON DTO binding, binary payloads,
query and option binding, Content-Format / Accept negotiation, Observe
metadata, generated .well-known/core output, and stable error responses.
Low-level route endpoint compatibility:
using CoAP;
using CoAP.Server;
using CoAP.Server.Routing;
using System.Linq;
using System.Threading.Tasks;
var server = new CoapServer();
var routes = CoapRouteEndpoint.Create(new[]
{
CoapRoute.Post(
"diagnostics/{target}/ping",
() => new DiagnosticsCoapResource(),
resource => resource.PingAsync())
});
server.Add(routes.ToArray());
server.Start();
sealed class DiagnosticsCoapResource : CoapResourceBase
{
public ValueTask<CoapRouteResult> PingAsync()
{
var target = RouteValues["target"];
var bytes = Payload;
var payload = System.Text.Encoding.UTF8.GetBytes("{\"ok\":true}");
return new ValueTask<CoapRouteResult>(
CoapRouteResult.Content(payload, MediaType.ApplicationJson)
.WithMaxAge(30)
.WithETag(new byte[] { 0x01, 0x02 })
.WithLocationPath($"diagnostics/{target}/ping"));
}
}DTLS PSK server endpoint:
using CoAP;
using CoAP.Channel;
using CoAP.Net;
using CoAP.Server;
var config = new CoapConfig();
var server = new CoapServer(config);
var keys = new Dictionary<string, string>
{
["device-1"] = "shared-secret",
};
server.AddEndPoint(new CoAPEndPoint(new DtlsPskChannel(5684, keys), config));
server.Start();dotnet pack CoAP.NET/CoAP.NET.csproj -c Release
dotnet pack CoAP.NET.SourceGeneration/CoAP.NET.SourceGeneration.csproj -c Release
dotnet pack CoAP.NET.AspNetCore/CoAP.NET.AspNetCore.csproj -c ReleaseThe core package is written to CoAP.NET/artifacts by default. The GitHub
Actions release workflow writes all publishable packages to the workflow
artifact directory before pushing them.
NuGet publishing is handled by
.github/workflows/publish-nuget.yml.
The workflow:
- builds the core package, ASP.NET Core adapter, source generator, Resource/MVC sample, and tests on branch pushes and pull requests;
- packs
IoTSharp.CoAP.NET,IoTSharp.CoAP.NET.AspNetCore, andIoTSharp.CoAP.NET.SourceGenerationfor release tags and manual release runs; - publishes to NuGet.org on
v*tags by using the organizationNUGET_API_KEYsecret; - supports manual runs with a version input and an explicit
publish_to_nugetswitch.
Run these commands from the SonnetDB/extensions/IoTSharp.CoAP.NET directory:
dotnet build CoAP.NET/CoAP.NET.csproj
dotnet build CoAP.Example/CoAP.Server/CoAP.Server.csproj
dotnet build CoAP.Example/CoAP.Client/CoAP.Client.csproj
dotnet test CoAP.Test/CoAP.Test.csprojThe baseline tests cover:
- Resource tree and discovery:
ResourceTreeTest,ResourceAttributesTest,ResourceTest. - Server start/stop and client request flow:
StartStopTest,CoapClientTest. - Blockwise transfer:
BlockwiseTransferTest,RandomAccessBlockTest. - Observe behavior:
CoapClientTest,MemoryLeakingMapTest. - Message and option compatibility:
MessageTypeTest,OptionTest,BlockOptionTest.
DTLS PSK transport is exposed through DtlsPskChannel and
DtlsPskClientChannel; C12 adds automated route + DTLS PSK smoke coverage in
CoapC12SmokeTest.
Run the C12 smoke tests and route benchmark from this directory:
dotnet test CoAP.Test/CoAP.Test.csproj -c Release --filter FullyQualifiedName~CoapC12SmokeTest
dotnet run -c Release --project CoAP.Benchmarks/CoAP.Benchmarks.csproj -- --filter *CoapRouteMatcherBenchmark*The release checklist, trim/AOT warning inventory, and pack verification steps are maintained in docs/c12-release-checklist.md.
This project preserves the original CoAP.NET BSD-style license. See LICENSE for details.
CoAP.NET is based on Californium, a CoAP framework in Java by Matthias Kovatsch, Dominique Im Obersteg, and Daniel Pauli at ETH Zurich.