JasonShave.Azure.Communication.Service.EventHandler.JobRouter 1.0.0-alpha-2022-10-10.1

This is a prerelease version of JasonShave.Azure.Communication.Service.EventHandler.JobRouter.
The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet add package JasonShave.Azure.Communication.Service.EventHandler.JobRouter --version 1.0.0-alpha-2022-10-10.1
NuGet\Install-Package JasonShave.Azure.Communication.Service.EventHandler.JobRouter -Version 1.0.0-alpha-2022-10-10.1
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="JasonShave.Azure.Communication.Service.EventHandler.JobRouter" Version="1.0.0-alpha-2022-10-10.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add JasonShave.Azure.Communication.Service.EventHandler.JobRouter --version 1.0.0-alpha-2022-10-10.1
#r "nuget: JasonShave.Azure.Communication.Service.EventHandler.JobRouter, 1.0.0-alpha-2022-10-10.1"
#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.
// Install JasonShave.Azure.Communication.Service.EventHandler.JobRouter as a Cake Addin
#addin nuget:?package=JasonShave.Azure.Communication.Service.EventHandler.JobRouter&version=1.0.0-alpha-2022-10-10.1&prerelease

// Install JasonShave.Azure.Communication.Service.EventHandler.JobRouter as a Cake Tool
#tool nuget:?package=JasonShave.Azure.Communication.Service.EventHandler.JobRouter&version=1.0.0-alpha-2022-10-10.1&prerelease

Azure Communication Services Event Handler Library

.NET

This repository contains libraries which act as a set of convenience layer services to the Azure.Communication.Service.CallAutomation and Azure.Communication.Service.JobRouter libraries currently in preview.

Problem statement

A common task developers must undertake with an event-driven platform is to deal with a common event payload which wraps a variation of models often denoted with a type identifier. Consider the following event, CallConnected which is 'wrapped' in an Azure.Messaging.CloudEvent type:

Azure.Messaging.CloudEvent

{
    "id": "7dec6eed-129c-43f3-a2bf-134ac1978168",
    "source": "calling/callConnections/441f1200-fd54-422e-9566-a867d187dca7",
    "type": "Microsoft.Communication.CallConnected",
    "data": {
        "callConnectionId": "441f1200-fd54-422e-9566-a867d187dca7",
        "serverCallId": "e42f9a50-c36d-493a-9cc0-2fc1cdc7b708",
        "correlationId": "7a659f41-bd0f-4bae-8ac0-6af79283e1bc"
    },
    "time": "2022-06-24T15:12:41.5556858+00:00",
    "specversion": "1.0",
    "datacontenttype": "application/json",
    "subject": "calling/callConnections/441f1200-fd54-422e-9566-a867d187dca7"
}

Since this event is triggered by a web hook callback, the API controller consuming this CloudEvent type must extract the body by reading the HttpRequest object, typically asynchronously, then deserialize it to it's proper type. The CloudEvent open specification provides a type property to aid developers in understanding the data payload type. The following example illustrates the cumbersome nature of handling different data payloads in a single CloudEvent envelope:

// get body from HttpRequest
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

// deserialize into an array of CloudEvent types
CloudEvent[] cloudEvents = JsonSerializer.Deserialize<CloudEvent[]>(requestBody);

foreach(var cloudEvent in cloudEvents)
{
    var @event = CallAutomationEventParser.Parse(cloudEvent);
    // conditional logic for every possible event type
    if (@event is CallConnected callConnected)
    {        
        // now you can invoke your action based on this event being cast to the correct type
    }
}

This conditional logic handling needs to be done by every customer for every possible event type which turns the focus of the developer away from their business problem and concerns them with the non-functional challenges.

Call Automation and/or Job Router Configuration

The following NuGet packages are available depending on if you want to handle Call Automation events, JobRouter events, or both.

Package Latest Details
EventHandler.CallAutomation Nuget Used with ACS Call Automation SDK
EventHandler.JobRouter Nuget Used with ACS Job Router SDK

For a typical .NET 6 web application, the following configuration can be made to wire up the publishers, event catalog, dispatcher, and allow you to subscribe to events from either platform.

  1. Add the following to your .NET 6 or higher Program.cs file:

    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddEventHandlerServices() //<--adds common event handling services
        .AddCallAutomationEventHandling() //<--adds support for Call Automation SDK events
        .AddJobRouterEventHandling(); //<--adds support for Job Router SDK events
    
    var app = builder.Build();
    app.Run();
    

Publishing CloudEvent and EventGridEvent messages

Leveraging .NET's dependency injection framework, add the IEventPublisher<Calling> or IEventPublisher<Router> to push Azure.Messaging.CloudEvent and Azure.Messaging.EventGrid messages into the services where their types are automatically cast, deserialized, and the correct event handler is invoked.

// .NET 6 'minimal API' to handle JobRouter Event Grid HTTP web hook subscription
app.MapPost("/api/jobRouter", (
    [FromBody] EventGridEvent[] eventGridEvents,
    IEventPublisher<Router> publisher) => publisher.Publish(eventGridEvents));

// .NET 6 'minimal API' to handle Call Automation mid-call web hook callbacks
app.MapPost("/api/calls/{contextId}", (
    [FromBody] CloudEvent[] cloudEvent,
    [FromRoute] string contextId,
    IEventPublisher<Calling> publisher) => publisher.Publish(@event.Data, contextId));

Subscribing and handling Call Automation and Job Router events

As mentioned above, the CloudEvent or EventGridEvent is pushed and the corresponding C# event is invoked and subscribed to. For the Call Automation SDK, incoming calls are delivered using Event Grid and mid-call events are delivered through web hook callbacks. Job Router uses Event Grid to deliver all events. The example below shows a .NET background service wiring up the event handler as follows:

public class MyService : BackgroundService
{
    public MyService(
        ICallAutomationEventSubscriber callAutomationEventSubscriber,
        IJobRouterEventSubscriber jobRouterSubscriber)
    {
        // subscribe to Call Automation and Job Router events
        callAutomationEventSubscriber.OnCallConnected += HandleCallConnected;
        jobRouterSubscriber.OnJobQueued += HandleJobQueued;
    }
    
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            Task.Delay(1000, cancellationToken);
        }
    }

    private async Task HandleCallConnected(CallConnected callConnected, string contextId) =>
        _logger.LogInformation($"Call connection ID: {callConnected.CallConnectionId} | Context: {contextId}");

    private Task HandleJobQueued(RouterJobQueued jobQueued, string contextId) =>
        _logger.LogInformation($"Job {jobQueued.JobId} in queue {jobQueued.QueueId}")
}

License

This project is licensed under the MIT License - see the LICENSE.md file for details.

Product Compatible and additional computed target framework versions.
.NET 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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated

Initial release.