Skip to content

hctv19/sdk-csharp

 
 

Repository files navigation

Build

sdk-csharp

.NET Standard 2.0 (C#) SDK for CloudEvents

The CloudNative.CloudEvents package provides utility methods and classes for creating, encoding, decoding, sending, and receiving CNCF CloudEvents.

CloudEvent

The CloudEvent class reflects the event envelope defined by the CNCF CloudEvents specification. It supports versions 0.1, 0.2, and 0.3 of the CloudEvents specification. The strongly typed API already reflects the 0.3 naming with backwards compatible property overrides for 0.2 that are explicitly marked as obsolete.

The default specification version is 0.3, you can override this by specifying the version explicitly: new CloudEvent(CloudEventsSpecVersion.V0_1). The SpecVersion property also allows the version to be switched, meaning you can receive a 0.1 event, switch the version number, and forward it as a 0.3 event.

0.1 0.2 0.3 Property name CLR type
eventID id id CloudEvent.Id System.String
eventType type type CloudEvent.Type System.String
cloudEventsVersion specversion specversion CloudEvent.SpecVersion System.String
eventTime time time CloudEvent.Time System.DateTime
source source source CloudEvent.Source System.Uri
- - subject CloudEvent.Source System.String
schemaUrl schemaurl schemaurl CloudEvent.SchemaUrl System.Uri
contentType contenttype datacontenttype CloudEvent.ContentType System.Net.Mime.ContentType
- - datacontentencoding CloudEvent.DataContentEncoding System.String
data data data CloudEvent.Data System.Object

The CloudEvent.Data property is object typed, and may hold any valid serializable CLR type. The following types have special handling:

  • System.String: In binary content mode, strings are copied into the transport message payload body using UTF-8 encoding.
  • System.Byte[]: In binary content mode, byte array content is copied into the message paylaod body without further transformation.
  • System.Stream: In binary content mode, stream content is copied into the message paylaod body without further transformation.

Any other data type is transformed using the given event formatter for the operation or the JSON formatter by default before being added to the transport payload body.

All extension attributes can be reached via the CloudEvent.GetAttributes() method, which returns the internal attribute collection. The internal collection performs all required validations.

If a CloudEvents-prefixed transport header, like an HTTP header, is string typed and the value is surrounded by '{' and '}' or '[' and ']', it is assumed to hold JSON content.

Extensions

CloudEvent extensions are represented by implementations of the ICloudEventExtension interface. The SDK includes strongly-typed implementations for all offical CloudEvents extensions:

Extension classes provide type-safe access to the extension attributes as well as implement the required validations and type mappings. An extension object is always created as an independent entity and is then attached to a CloudEvent instance. Once attached, the extension object's attributes are merged into the CloudEvent instance.

This snippet shows how to create a CloudEvent with an extension:

 var cloudEvent = new CloudEvent(
    "com.github.pull.create",
    new Uri("https://github.com/cloudevents/spec/pull/123"),
    new DistributedTracingExtension()
    {
        TraceParent = "value",
        TraceState = "value"
    })
{
    ContentType = new ContentType("application/json"),
    Data = "[]"
};

The extension can later be accessed via the Extension<T>() method:

 var s = cloudEvent.Extension<DistributedTracingExtension>().TraceParent

All APIs where a CloudEvent is constructed from an incoming event (or request or response) allow for extension instances to be added via their respective methods, and the extensions are invoked in the mapping process (for instance, to extract information from headers that deviate from the CloudEvents default mapping).

For example, the server-side mapping for HttpRequestMessage allows adding extensions like this:

public async Task<HttpResponseMessage> Run( HttpRequestMessage req, ILogger log)
{
    var cloudEvent = req.ToCloudEvent(new DistributedTracingExtension());
}

Transport Bindings

This SDK helps with mapping CloudEvents to and from messages or transport frames of popular .NET clients in such a way as to be agnostic of your application's choices of how you want to send an event (be it via HTTP PUT or POST) or how you want to handle settlement of transfers in AMQP or MQTT. The transport binding classes and extensions therefore don't wrap the send and receive operations; you still use the native API of the respective library.

HTTP - System.Net.Http.HttpClient

The .NET HttpClient uses the HttpContent abstraction to wrap payloads for sending requests that carry entity bodies.

This SDK provides a [CloudEventContent] class derived from HttpContent that can be created from a CloudEvent instance, the desired ContentMode, and an event formatter.

var cloudEvent = new CloudEvent("com.example.myevent", new Uri("urn:example-com:mysource"))
{
    ContentType = new ContentType(MediaTypeNames.Application.Json),
    Data = JsonConvert.SerializeObject("hey there!")
};

var content = new CloudEventContent( cloudEvent, 
                                     ContentMode.Structured, 
                                     new JsonEventFormatter());

var httpClient = new HttpClient();
var result = (await httpClient.PostAsync(this.Url, content));

For responses, HttpClient puts all custom headers onto the HttpResponseMessage rather than on the carried HttpContent instance. Therefore, if an event is retrieved with HttpClient (for instance, from a queue-like structure) the CloudEvent is created from the response message object rather than the content object using the ToCloudEvent() extension method on HttpResponseMessage:

var httpClient = new HttpClient();
// delete and receive message from top of the queue
var result = await httpClient.DeleteAsync(new Uri("https://example.com/queue/messages/top"));
if (HttpStatusCode.OK == result.StatusCode) {
   var receivedCloudEvent = await result.ToCloudEvent();
}

HTTP - System.Net.HttpWebRequest

If your application uses the HttpWebRequest client, you can copy a CloudEvent into the request payload in structured or binary mode:

HttpWebRequest httpWebRequest = WebRequest.CreateHttp("https://example.com/target");
httpWebRequest.Method = "POST";
await httpWebRequest.CopyFromAsync(cloudEvent, ContentMode.Structured, new JsonEventFormatter());

Bear in mind that the Method property must be set to an HTTP method that allows an entity body to be sent, otherwise the copy operation will fail.

HTTP - System.Net.HttpListener (HttpRequestMessage)

On the server-side, you can extract a CloudEvent from the server-side HttpRequestMessage with the ToCloudEventAsync() extension. If your code handles HttpRequestContext, you will use the Request property:

var cloudEvent = await context.Request.ToCloudEventAsync();

If you use a functions framework that lets you handle HttpResponseMessage and return HttpResponseMessage, you will call the extension on the request object directly:

public async Task<HttpResponseMessage> Run( HttpRequestMessage req, ILogger log)
{
    var cloudEvent = await req.ToCloudEventAsync();
}

The extension implementation will read the ContentType header of the incoming request and automatically select the correct built-in event format decoder. Your code can always pass an overriding format decoder instance as the first argument if needed.

If your HTTP handler needs to return a CloudEvent, you copy the CloudEvent into the response with the CopyFromAsync() extension method:

var cloudEvent = new CloudEvent("com.example.myevent", new Uri("urn:example-com:mysource"))
{
    ContentType = new ContentType(MediaTypeNames.Application.Json),
    Data = JsonConvert.SerializeObject("hey there!")
};

await context.Response.CopyFromAsync(cloudEvent, 
                                     ContentMode.Structured, 
                                     new JsonEventFormatter());
context.Response.StatusCode = (int)HttpStatusCode.OK; 

AMQP

The SDK provides extensions for the AMQPNetLite package.

For AMQP support, you must reference the CloudNative.CloudEvents.Mqtt assembly and reference the namespace in your code with using CloudNative.CloudEvents.Mqtt.

The AmqpCloudEventMessage extends the AMQPNetLite.Message class. The constructor allows creating a new AMQP message that holds a CloudEvent in either structured or binary content mode.

var cloudEvent = new CloudEvent("com.example.myevent", new Uri("urn:example-com:mysource"))
{
    ContentType = new ContentType(MediaTypeNames.Application.Json),
    Data = JsonConvert.SerializeObject("hey there!")
};

var message = new AmqpCloudEventMessage( cloudEvent, 
                                         ContentMode.Structured, 
                                         new JsonEventFormatter());

For mapping a received Message to a CloudEvent, you can use the ToCloudEvent() method:

   var receivedCloudEvent = await message.ToCloudEvent();

MQTT

The SDK provides extensions for the MQTTnet package. For MQTT support, you must reference the CloudNative.CloudEvents.Mqtt assembly and reference the namespace in your code with using CloudNative.CloudEvents.Mqtt.

The MqttCloudEventMessage extends the MqttApplicationMessage class. The constructor allows creating a new MQTT message that holds a CloudEvent in structured content mode.

var cloudEvent = new CloudEvent("com.example.myevent", new Uri("urn:example-com:mysource"))
{
    ContentType = new ContentType(MediaTypeNames.Application.Json),
    Data = JsonConvert.SerializeObject("hey there!")
};

var message = new MqttCloudEventMessage( cloudEvent, 
                                         new JsonEventFormatter());

For mapping a received MqttApplicationMessage to a CloudEvent, you can use the ToCloudEvent() method:

   var receivedCloudEvent = await message.ToCloudEvent();

About

CSharp SDK for CloudEvents

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C# 100.0%