Skip to content

Add Initial support for CBOR protocol including extension package and Marshaller generators #3879

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: cbor-protocol
Choose a base branch
from

Conversation

muhammad-othman
Copy link
Member

@muhammad-othman muhammad-othman commented Jun 12, 2025

Description

This PR introduces foundational support for the smithy-rpc-v2-cbor protocol in the AWS SDK for .NET. The changes are structured across three commits:

  • 1c3f3aa Add AWSSDK.Extensions.CborProtocol project which includes the following:
    • CborWriterPool: Reduces allocations by pooling CborWriter instances in a thread-safe way.
    • CborMarshallerContext: Common context used by marshallers to write CBOR payloads.
    • Isolates CBOR-specific dependencies System.Formats.Cbor from the Core SDK and keeps non-CBOR services unaffected.
  • f61c4f5 Add CBOR marshaller generators
  • f1a5ae7 Generate sample marshallers for CloudWatch.
    • These marshallers can be used as reference for reviewing the generator output.
    • Will revert this commit before merging the PR.

Motivation and Context

  • DOTNET-8158
  • DOTNET-8159
  • DOTNET-8160

Testing

Added smithy-rpc-v2-cbor to few service models protocols, generated the marshallers, executed some requests using these marshallers and validated that the serialized content is as expected and that the requests were handled correctly by these services.

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

License

  • I confirm that this pull request can be released under the Apache 2 license

private static readonly ConcurrentBag<CborWriter> _pool = new ConcurrentBag<CborWriter>();

// Maximum number of CborWriter instances the pool can hold
private static int _maxPoolSize = 16;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current value of _maxPoolSize is temporary, I need evaluate and test it more before merging the feature branch.

@normj normj self-requested a review June 13, 2025 07:33
@philasmar philasmar requested a review from peterrsongg June 13, 2025 17:25
Copy link
Contributor

@peterrsongg peterrsongg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just some minor comments, but also it's kind of hard to tell if it is working correctly or not without the protocol tests for the marshallers. Were you planning on adding that as part of this PR?

</Choose>

<ItemGroup>
<PackageReference Include="System.Formats.Cbor" Version="9.0.5" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a general question, but do you have plans to also include these new dependencies in the build system when copying over the dll's? I had to do that when adding System.Text.JSON as an example

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should part of the build system task that we added, will mention that on the task's decription so we don't miss that.

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.1;net8.0</TargetFrameworks>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need netcoreapp3.1 in here if cbor is only supported in net8 and netstandard?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should work on netcoreapp3.1 too, it will just show a warning.

return;
}

if (value % 1 == 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this safe to do? I don't know much about CBOR but it seems that if the user passes in a float value they'd want to keep that extra precision instead of writing it as an int. Am I missing something here? Since it is binary does it not matter?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When if (value % 1 == 0) is true, then we don't have anything after the decimal point to keep. It was part of the SEP to send the numbers as the smallest version possible that doesn't lose any data.

/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public IRequest Marshall(AmazonWebServiceRequest input)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whitespace seems to be off here. or is it just the github ui?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably, It looks good when generated though which should matter more, will double check if I can do something about it without messing up the generated files.

throw new System.InvalidOperationException("TargetPrefix is required for CBOR based services.");
}
#>
request.ResourcePath = "<#=$"service/{this.Config.ServiceModel.TargetPrefix}/operation/{this.Operation.Name}"#>";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the prefix? The SEP states it as a MUST

Every request for the rpcv2Cbor protocol MUST be sent to a URL with the following form: {prefix?}/service/{serviceName}/operation/{operationName}

I couldn't find in the cloudwatch logs service model where to even get this prefix though

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is something I talked about with the SEP writers in the CBOR channel, it doesn't exist now for CloudWatch but it must be added before it uses CBOR.
Also there is additional details in the SEP few lines after the line you quoted, and it mentions how the serviceName can be found for smithy and that for C2J it should be TargetPrefix, thats why I added this exception to be safe if they forgot to add it for some reason.

using AWSSDK.Extensions.CborProtocol.Internal;

#pragma warning disable CS0612,CS0618
namespace <#= this.Config.Namespace #>.Model.Internal.MarshallTransformations
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: weird spacing here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe another github UI thing, will double check this one too.

Copy link
Member Author

@muhammad-othman muhammad-othman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@peterrsongg I understand that verifiying that everything work is kinda hard, but this PR is already big enough that I didn't want and increase its size with the Protocol tests which are my next task. Though did some manual testing with the services to be sure.
Also we are targetting a feature branch here, so rest assured that we don't release this without the Protocol tests :D

</Choose>

<ItemGroup>
<PackageReference Include="System.Formats.Cbor" Version="9.0.5" />
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should part of the build system task that we added, will mention that on the task's decription so we don't miss that.

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.1;net8.0</TargetFrameworks>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should work on netcoreapp3.1 too, it will just show a warning.

return;
}

if (value % 1 == 0)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When if (value % 1 == 0) is true, then we don't have anything after the decimal point to keep. It was part of the SEP to send the numbers as the smallest version possible that doesn't lose any data.

throw new System.InvalidOperationException("TargetPrefix is required for CBOR based services.");
}
#>
request.ResourcePath = "<#=$"service/{this.Config.ServiceModel.TargetPrefix}/operation/{this.Operation.Name}"#>";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is something I talked about with the SEP writers in the CBOR channel, it doesn't exist now for CloudWatch but it must be added before it uses CBOR.
Also there is additional details in the SEP few lines after the line you quoted, and it mentions how the serviceName can be found for smithy and that for C2J it should be TargetPrefix, thats why I added this exception to be safe if they forgot to add it for some reason.

using AWSSDK.Extensions.CborProtocol.Internal;

#pragma warning disable CS0612,CS0618
namespace <#= this.Config.Namespace #>.Model.Internal.MarshallTransformations
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe another github UI thing, will double check this one too.

/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public IRequest Marshall(AmazonWebServiceRequest input)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably, It looks good when generated though which should matter more, will double check if I can do something about it without messing up the generated files.

Copy link
Contributor

@peterrsongg peterrsongg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving, knowing that this may change when the protocol tests are added

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants