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 0000000..5b0e6d7 Binary files /dev/null and b/docs/docs/assets/images/favicon.ico differ 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..ab44dc8 --- /dev/null +++ b/docs/docs/getting-started.md @@ -0,0 +1,290 @@ +# Getting Started + +**Notice:** *This library is still in active development and has not been published to NuGet.org yet.* + +Add the `AWS.Messaging` NuGet package to your project: +``` +dotnet add package AWS.Messaging --prerelease +``` + +The framework integrates with .NET's [dependency injection (DI) service container](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection). You can configure the framework during your application's startup by calling `AddAWSMessageBus` to add it to the DI container. + +```csharp +var builder = WebApplication.CreateBuilder(args); + +// Register the AWS Message Processing Framework for .NET +builder.Services.AddAWSMessageBus(builder => +{ + // Register that you'll publish messages of type ChatMessage to an existing queue + builder.AddSQSPublisher("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd"); +}); +``` + +The framework supports publishing one or more message types, processing one or more message types, or doing both in the same application. + +# Publishing Messages + +The following code shows a configuration for an application that is publishing different message types to different AWS services. + +```csharp +var builder = WebApplication.CreateBuilder(args); + +// Register the AWS Message Processing Framework for .NET +builder.Services.AddAWSMessageBus(builder => +{ + // Register that you'll publish messages of type ChatMessage to an existing queue + builder.AddSQSPublisher("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd"); + + // Register that you'll publish messages of type OrderInfo to an existing SNS topic + builder.AddSNSPublisher("arn:aws:sns:us-west-2:012345678910:MyAppProd"); + + // Register that you'll publish messages of type FoodItem to an existing EventBridge bus + builder.AddEventBridgePublisher("arn:aws:events:us-west-2:012345678910:event-bus/default"); + + // Configure serialization options for how the message types are serialized and deserialized to JSON + builder.ConfigureSerializationOptions(options => + { + options.SystemTextJsonOptions = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + }); +}); +``` + +Once you have registered the framework during startup, inject the `IMessagePublisher` into your code and call its `PublishAsync` method to publish a message. In the following example, an ASP.NET MVC controller receives a `ChatMessage` from the user and then publishes that same object to SQS. + +```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) + { + // Perform business and validation logic on the ChatMessage here + if (message == null) + { + return BadRequest("A chat message was not submitted. Unable to forward to the message queue."); + } + if (string.IsNullOrEmpty(message.MessageDescription)) + { + return BadRequest("The MessageDescription cannot be null or empty."); + } + + // Publish the message to SQS, using the injected IMessagePublisher + await _messagePublisher.PublishAsync(message); + + return Ok(); + } +} +``` +## Service-specific publishers + +The example shown above uses the generic `IMessagePublisher`, which can publish to any supported AWS service based on the configured message type. The framework also provides *service-specific publishers* for SQS, SNS and EventBridge. These specific publishers expose options that only apply to that service, and can be injected using the types `ISQSPublisher`, `ISNSPublisher` and `IEventBridgePublisher`. + +For example, when publishing messages to an SQS FIFO queue, you must set the appropriate [message group ID](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-key-terms.html). The following code shows the `ChatMessage` example again, but now using an `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) + { + // Perform business and validation logic on the ChatMessage here + if (message == null) + { + return BadRequest("A chat message was not submitted. Unable to forward to the message queue."); + } + if (string.IsNullOrEmpty(message.MessageDescription)) + { + return BadRequest("The MessageDescription cannot be null or empty."); + } + + // Publish the message to SQS using the injected ISQSPublisher, with SQS-specific options + await _sqsPublisher.PublishAsync(message, new SQSOptions + { + DelaySeconds = , + MessageAttributes = , + MessageDeduplicationId = , + MessageGroupId = + }); + + return Ok(); + } +} +``` + +The same can be done for SNS and EventBridge, 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 =