From c8711f0b60e14da9e917bf6a473903608943f2b6 Mon Sep 17 00:00:00 2001 From: Phil Asmar Date: Wed, 6 Dec 2023 10:44:18 -0500 Subject: [PATCH 1/3] docs: create a documentation and API reference site --- .github/workflows/doc-site.yml | 47 +++++ .gitignore | 6 +- docs/docfx.json | 52 +++++ docs/docs/assets/images/aws-logo.svg | 1 + docs/docs/assets/images/favicon.ico | Bin 0 -> 114183 bytes docs/{ => docs}/assets/images/publishers.png | Bin docs/{ => docs}/assets/images/subscribers.png | Bin .../message-processing-framework-design.md | 0 .../message-source-computation-design.md | 0 .../message-visibility-timeout-handling.md | 0 docs/{ => docs}/design/telemetry-design.md | 0 docs/docs/getting-started.md | 196 ++++++++++++++++++ docs/docs/overview.md | 39 ++++ docs/docs/toc.yml | 16 ++ docs/filter.yml | 7 + docs/index.md | 4 + .../partials/class.header.tmpl.partial | 139 +++++++++++++ docs/template/public/main.js | 9 + docs/toc.yml | 4 + 19 files changed, 519 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/doc-site.yml create mode 100644 docs/docfx.json create mode 100644 docs/docs/assets/images/aws-logo.svg create mode 100644 docs/docs/assets/images/favicon.ico rename docs/{ => docs}/assets/images/publishers.png (100%) rename docs/{ => docs}/assets/images/subscribers.png (100%) rename docs/{ => docs}/design/message-processing-framework-design.md (100%) rename docs/{ => docs}/design/message-source-computation-design.md (100%) rename docs/{ => docs}/design/message-visibility-timeout-handling.md (100%) rename docs/{ => docs}/design/telemetry-design.md (100%) create mode 100644 docs/docs/getting-started.md create mode 100644 docs/docs/overview.md create mode 100644 docs/docs/toc.yml create mode 100644 docs/filter.yml create mode 100644 docs/index.md create mode 100644 docs/template/partials/class.header.tmpl.partial create mode 100644 docs/template/public/main.js create mode 100644 docs/toc.yml diff --git a/.github/workflows/doc-site.yml b/.github/workflows/doc-site.yml new file mode 100644 index 0000000..eec8a82 --- /dev/null +++ b/.github/workflows/doc-site.yml @@ -0,0 +1,47 @@ +name: Generate Documentation and API Reference + +# Trigger the action on push to main +on: + push: + branches: + - main + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + publish-docs: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Dotnet Setup + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 8.x + + - run: dotnet tool update -g docfx --version 2.74.0 + - run: docfx docs/docfx.json + + - name: Setup Pages + uses: actions/configure-pages@v3 + - name: Upload artifact + uses: actions/upload-pages-artifact@v2 + with: + # Upload entire repository + path: 'docs/_site' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/.gitignore b/.gitignore index 7e48df6..d23b224 100644 --- a/.gitignore +++ b/.gitignore @@ -477,4 +477,8 @@ $RECYCLE.BIN/ *.lnk # JetBrains Rider cache/options directory -.idea/ \ No newline at end of file +.idea/ + +# DocFx +docs/_site/ +docs/api/ \ No newline at end of file diff --git a/docs/docfx.json b/docs/docfx.json new file mode 100644 index 0000000..2142180 --- /dev/null +++ b/docs/docfx.json @@ -0,0 +1,52 @@ +{ + "metadata": [ + { + "src": [ + { + "src": "../src", + "files": [ + "**/*.csproj" + ] + } + ], + "dest": "api", + "filter": "filter.yml" + } + ], + "build": { + "content": [ + { + "files": [ + "**/*.{md,yml}" + ], + "exclude": [ + "_site/**", + "filter.yml" + ] + } + ], + "resource": [ + { + "files": [ + "docs/assets/images/**" + ] + } + ], + "output": "_site", + "template": [ + "default", + "modern", + "template" + ], + "globalMetadata": { + "_appName": "", + "_appTitle": "AWS Message Processing Framework for .NET", + "_appLogoPath": "docs/assets/images/aws-logo.svg", + "_appFaviconPath": "docs/assets/images/favicon.ico", + "_enableSearch": true, + "pdf": false, + "_disableContribution": true, + "_appFooter": "
© 2023, Amazon Web Services, Inc. or its affiliates. All rights reserved.
" + } + } +} \ No newline at end of file diff --git a/docs/docs/assets/images/aws-logo.svg b/docs/docs/assets/images/aws-logo.svg new file mode 100644 index 0000000..c0dbe69 --- /dev/null +++ b/docs/docs/assets/images/aws-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/docs/assets/images/favicon.ico b/docs/docs/assets/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5b0e6d794265dfe91019a0695b65de31f569875c GIT binary patch literal 114183 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 literal 0 HcmV?d00001 diff --git a/docs/assets/images/publishers.png b/docs/docs/assets/images/publishers.png similarity index 100% rename from docs/assets/images/publishers.png rename to docs/docs/assets/images/publishers.png diff --git a/docs/assets/images/subscribers.png b/docs/docs/assets/images/subscribers.png similarity index 100% rename from docs/assets/images/subscribers.png rename to docs/docs/assets/images/subscribers.png diff --git a/docs/design/message-processing-framework-design.md b/docs/docs/design/message-processing-framework-design.md similarity index 100% rename from docs/design/message-processing-framework-design.md rename to docs/docs/design/message-processing-framework-design.md diff --git a/docs/design/message-source-computation-design.md b/docs/docs/design/message-source-computation-design.md similarity index 100% rename from docs/design/message-source-computation-design.md rename to docs/docs/design/message-source-computation-design.md diff --git a/docs/design/message-visibility-timeout-handling.md b/docs/docs/design/message-visibility-timeout-handling.md similarity index 100% rename from docs/design/message-visibility-timeout-handling.md rename to docs/docs/design/message-visibility-timeout-handling.md diff --git a/docs/design/telemetry-design.md b/docs/docs/design/telemetry-design.md similarity index 100% rename from docs/design/telemetry-design.md rename to docs/docs/design/telemetry-design.md diff --git a/docs/docs/getting-started.md b/docs/docs/getting-started.md new file mode 100644 index 0000000..1df8812 --- /dev/null +++ b/docs/docs/getting-started.md @@ -0,0 +1,196 @@ +# Getting Started + +Add the `AWS.Messaging` NuGet package to your project +``` +dotnet add package AWS.Messaging +``` + +The framework integrates with Microsoft's dependency injection (DI) container. This can be done in your application startup by calling `AddAWSMessageBus` to add the AWS Message Processing Framework for .NET to the DI container. + +```csharp +var builder = WebApplication.CreateBuilder(args); +// Register the AWS Message Processing Framework for .NET +builder.Services.AddAWSMessageBus(builder => +{ + // Register a .NET object to an SQS Queue + builder.AddSQSPublisher("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd"); +}); +``` + +The message bus allows for adding the necessary configuration to support applications that are publishing messages, processing messages or doing both at the same time. + +Sample configuration for a `Publisher`: + +```csharp +var builder = WebApplication.CreateBuilder(args); + +// Register the AWS Message Processing Framework for .NET +builder.Services.AddAWSMessageBus(builder => +{ + // Register a .NET object to an SQS Queue + builder.AddSQSPublisher("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd"); + + // Register a .NET object to an SNS Topic + builder.AddSNSPublisher("arn:aws:sns:us-west-2:012345678910:MyAppProd"); + + // Register a .NET object to an EventBridge Event Bus + builder.AddEventBridgePublisher("arn:aws:events:us-west-2:012345678910:event-bus/default"); + + // Configure serialization options + builder.ConfigureSerializationOptions(options => + { + options.SystemTextJsonOptions = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }; + }); +}); +``` + +Once you have registered the framework in the DI container, all you need to publish a message is inject the `IMessagePublisher` into your code and call the `PublishAsync` method. + +Here is an example showing a sample publisher for a hypothetical `ChatMessage` message. + +```csharp +[ApiController] +[Route("[controller]")] +public class PublisherController : ControllerBase +{ + private readonly IMessagePublisher _messagePublisher; + + public PublisherController(IMessagePublisher messagePublisher) + { + _messagePublisher = messagePublisher; + } + + [HttpPost("chatmessage", Name = "Chat Message")] + public async Task PublishChatMessage([FromBody] ChatMessage message) + { + // Add business and validation logic here + + if (message == null) + { + return BadRequest("A chat message was not used."); + } + if (string.IsNullOrEmpty(message.MessageDescription)) + { + return BadRequest("The MessageDescription cannot be null or empty."); + } + + await _messagePublisher.PublishAsync(message); + + return Ok(); + } +} +``` + +If your application is a subscriber, your need to implement a message handler `IMessageHandler` interface for the message you wish to process. The message type and message handler are set up in the project startup. + +Sample configuration for a `Subscriber`: + +```csharp +await Host.CreateDefaultBuilder(args) + .ConfigureServices(services => + { + // Register the AWS Message Processing Framework for .NET + services.AddAWSMessageBus(builder => + { + // Register an SQS Queue for the message pump to poll for messages + builder.AddSQSPoller("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd"); + + // Register all IMessageHandler implementations with the message type they should process + builder.AddMessageHandler(); + }); + }) + .Build() + .RunAsync(); +``` + +Here is an example showing a sample message handler for a hypothetical `ChatMessage` message. + +```csharp +public class ChatMessageHandler : IMessageHandler +{ + public Task HandleAsync(MessageEnvelope messageEnvelope, CancellationToken token = default) + { + // Add business and validation logic here + + if (messageEnvelope == null) + { + return Task.FromResult(MessageProcessStatus.Failed()); + } + + if (messageEnvelope.Message == null) + { + return Task.FromResult(MessageProcessStatus.Failed()); + } + + var message = messageEnvelope.Message; + + Console.WriteLine($"Message Description: {message.MessageDescription}"); + + return Task.FromResult(MessageProcessStatus.Success()); + } +} +``` + +## Using service-specific publishers + +The AWS Message Processing Framework for .NET exposes service-specific publishers for the supported services SQS, SNS and EventBridge. These publishers are accessible through the DI container via the types `ISQSPublisher`, `ISNSPublisher` and `IEventBridgePublisher`. When using these publishers, you have access to service-specific options/configurations that can be set when publishing a message. + +An example of using `ISQSPublisher` to set SQS-specific options: +```csharp +public class PublisherController : ControllerBase +{ + private readonly ISQSPublisher _sqsPublisher; + + public PublisherController(ISQSPublisher sqsPublisher) + { + _sqsPublisher = sqsPublisher; + } + + [HttpPost("chatmessage", Name = "Chat Message")] + public async Task PublishChatMessage([FromBody] ChatMessage message) + { + if (message == null) + { + return BadRequest("A chat message was not used."); + } + if (string.IsNullOrEmpty(message.MessageDescription)) + { + return BadRequest("The MessageDescription cannot be null or empty."); + } + + await _sqsPublisher.PublishAsync(message, new SQSOptions + { + DelaySeconds = , + MessageAttributes = , + MessageDeduplicationId = , + MessageGroupId = + }); + + return Ok(); + } +} +``` + +The same can be done for `SNS` and `EventBridge` publishers using `ISNSPublisher` and `IEventBridgePublisher` respectively: +```csharp +await _snsPublisher.PublishAsync(message, new SNSOptions +{ + Subject = , + MessageAttributes = , + MessageDeduplicationId = , + MessageGroupId = +}); +``` +```csharp +await _eventBridgePublisher.PublishAsync(message, new EventBridgeOptions +{ + DetailType = , + Resources = , + Source = , + Time =