From 8454b3b978bc6fa27885cc58c489a700842d5552 Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2026 09:45:39 -0400 Subject: [PATCH 1/7] fix(csharp): honor ClientOptions global headers, fix README snippets and XML docs, add docs/NuGet metadata config (#17471) * fix(csharp-sdk): route literal global headers through ClientOptions Co-Authored-By: bot_apk * fix(csharp-sdk): generate valid README snippets and populate requirements Co-Authored-By: bot_apk * fix(csharp-sdk): emit well-formed XML doc comments Co-Authored-By: bot_apk * feat(csharp-sdk): support XML docs and NuGet package metadata config Co-Authored-By: bot_apk * chore(csharp-sdk): regenerate seed fixtures Co-Authored-By: bot_apk * fix(csharp): emit valid crefs for union type docs and websocket doc comments Co-Authored-By: bot_apk * fix(csharp): escape markup characters in doc comment attribute values Co-Authored-By: bot_apk * chore(seed): update jsonschema snapshot for csharp-xml-entities fixture Co-Authored-By: bot_apk * chore(seed): update ir snapshots for csharp-xml-entities fixture Co-Authored-By: bot_apk --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: bot_apk --- generators/csharp/base/src/asIs/Extensions.cs | 2 + .../src/asIs/NullableAttribute.Template.cs | 8 +- .../csharp/base/src/asIs/Optional.Template.cs | 8 +- .../src/asIs/OptionalAttribute.Template.cs | 12 +- .../src/asIs/QueryStringBuilder.Template.cs | 2 +- .../src/asIs/WebSockets/Query.Template.cs | 2 +- .../WebSockets/WebSocketClient.Template.cs | 4 + .../test/Utils/OptionalComparer.Template.cs | 2 +- .../csharp/base/src/project/CsharpProject.ts | 106 +- .../project/__test__/targetFrameworks.test.ts | 33 + generators/csharp/base/src/project/index.ts | 1 + .../base/src/project/targetFrameworks.ts | 50 + .../codegen/src/__test__/XmlDocWriter.test.ts | 87 ++ .../csharp/codegen/src/ast/core/Writer.ts | 27 +- .../codegen/src/ast/core/XmlDocWriter.ts | 119 +- .../codegen/src/context/generation-info.ts | 4 + .../src/custom-config/CsharpConfigSchema.ts | 43 + .../UndiscriminatedUnionGenerator.ts | 16 +- .../csharp/model/src/union/UnionGenerator.ts | 18 +- .../feat-docs-and-package-metadata.yml | 17 + .../fix-client-options-global-headers.yml | 16 + .../fix-doc-comment-attribute-escaping.yml | 6 + .../unreleased/fix-readme-requirements.yml | 9 + .../unreleased/fix-readme-snippets.yml | 14 + .../fix-union-cref-doc-comments.yml | 8 + .../unreleased/fix-xml-doc-comments.yml | 8 + .../sdk/src/options/BaseOptionsGenerator.ts | 16 +- .../sdk/src/options/ClientOptionsGenerator.ts | 12 +- .../sdk/src/readme/ReadmeConfigBuilder.ts | 3 +- .../sdk/src/readme/ReadmeSnippetBuilder.ts | 6 +- .../src/root-client/RootClientGenerator.ts | 41 +- .../type__TimeZoneModel.json | 22 + .../test-definitions/csharp-xml-entities.json | 66 + .../test-definitions/csharp-xml-entities.json | 220 +++- .../fix-empty-readme-requirements.yml | 7 + .../src/readme/ReadmeGenerator.ts | 2 +- seed/csharp-sdk/accept-header/README.md | 9 +- .../SeedAccept.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedAccept/Core/Extensions.cs | 2 + .../src/SeedAccept/Core/NullableAttribute.cs | 8 +- .../src/SeedAccept/Core/Optional.cs | 8 +- .../src/SeedAccept/Core/OptionalAttribute.cs | 12 +- .../src/SeedAccept/Core/QueryStringBuilder.cs | 2 +- .../src/SeedAccept/SeedAccept.csproj | 4 + seed/csharp-sdk/alias-extends/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedAliasExtends/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedAliasExtends/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedAliasExtends/SeedAliasExtends.csproj | 4 + seed/csharp-sdk/alias/README.md | 9 +- .../SeedAlias.Test/Utils/OptionalComparer.cs | 2 +- .../alias/src/SeedAlias/Core/Extensions.cs | 2 + .../src/SeedAlias/Core/NullableAttribute.cs | 8 +- .../alias/src/SeedAlias/Core/Optional.cs | 8 +- .../src/SeedAlias/Core/OptionalAttribute.cs | 12 +- .../src/SeedAlias/Core/QueryStringBuilder.cs | 2 +- .../alias/src/SeedAlias/SeedAlias.csproj | 4 + seed/csharp-sdk/allof-inline/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../allof-inline/src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../allof-inline/src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/allof/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../allof/src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../allof/src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../allof/src/SeedApi/SeedApi.csproj | 4 + .../any-auth/no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedAnyAuth/Core/Extensions.cs | 2 + .../src/SeedAnyAuth/Core/NullableAttribute.cs | 8 +- .../src/SeedAnyAuth/Core/Optional.cs | 8 +- .../src/SeedAnyAuth/Core/OptionalAttribute.cs | 12 +- .../SeedAnyAuth/Core/QueryStringBuilder.cs | 2 +- .../src/SeedAnyAuth/SeedAnyAuth.csproj | 4 + .../any-auth/prefer-explicit-auth/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedAnyAuth/Core/Extensions.cs | 2 + .../src/SeedAnyAuth/Core/NullableAttribute.cs | 8 +- .../src/SeedAnyAuth/Core/Optional.cs | 8 +- .../src/SeedAnyAuth/Core/OptionalAttribute.cs | 12 +- .../SeedAnyAuth/Core/QueryStringBuilder.cs | 2 +- .../src/SeedAnyAuth/SeedAnyAuth.csproj | 4 + .../api-wide-base-path-with-default/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/api-wide-base-path/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedApiWideBasePath/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedApiWideBasePath/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedApiWideBasePath.csproj | 4 + seed/csharp-sdk/audiences/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedAudiences/Core/Extensions.cs | 2 + .../SeedAudiences/Core/NullableAttribute.cs | 8 +- .../src/SeedAudiences/Core/Optional.cs | 8 +- .../SeedAudiences/Core/OptionalAttribute.cs | 12 +- .../SeedAudiences/Core/QueryStringBuilder.cs | 2 +- .../src/SeedAudiences/SeedAudiences.csproj | 4 + .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedBasicAuthEnvironmentVariables.csproj | 4 + .../basic-auth-pw-omitted/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedBasicAuthPwOmitted/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedBasicAuthPwOmitted/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedBasicAuthPwOmitted.csproj | 4 + .../basic-auth/no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedBasicAuth/Core/Extensions.cs | 2 + .../SeedBasicAuth/Core/NullableAttribute.cs | 8 +- .../src/SeedBasicAuth/Core/Optional.cs | 8 +- .../SeedBasicAuth/Core/OptionalAttribute.cs | 12 +- .../SeedBasicAuth/Core/QueryStringBuilder.cs | 2 +- .../src/SeedBasicAuth/SeedBasicAuth.csproj | 4 + .../unified-client-options/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedBasicAuth/Core/Extensions.cs | 2 + .../SeedBasicAuth/Core/NullableAttribute.cs | 8 +- .../src/SeedBasicAuth/Core/Optional.cs | 8 +- .../SeedBasicAuth/Core/OptionalAttribute.cs | 12 +- .../SeedBasicAuth/Core/QueryStringBuilder.cs | 2 +- .../src/SeedBasicAuth/SeedBasicAuth.csproj | 4 + .../basic-auth/wire-tests/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedBasicAuth/Core/Extensions.cs | 2 + .../SeedBasicAuth/Core/NullableAttribute.cs | 8 +- .../src/SeedBasicAuth/Core/Optional.cs | 8 +- .../SeedBasicAuth/Core/OptionalAttribute.cs | 12 +- .../SeedBasicAuth/Core/QueryStringBuilder.cs | 2 +- .../src/SeedBasicAuth/SeedBasicAuth.csproj | 4 + .../no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/Public/ClientOptions.cs | 1 + .../Core/QueryStringBuilder.cs | 2 +- .../SeedBearerTokenEnvironmentVariable.csproj | 4 + .../unified-client-options/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/Public/ClientOptions.cs | 1 + .../Core/QueryStringBuilder.cs | 2 +- .../SeedBearerTokenEnvironmentVariable.csproj | 4 + seed/csharp-sdk/bytes-download/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedBytesDownload/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedBytesDownload/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedBytesDownload.csproj | 4 + .../Utils/OptionalComparer.cs | 2 +- .../src/SeedBytesUpload/Core/Extensions.cs | 2 + .../SeedBytesUpload/Core/NullableAttribute.cs | 8 +- .../src/SeedBytesUpload/Core/Optional.cs | 8 +- .../SeedBytesUpload/Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedBytesUpload/SeedBytesUpload.csproj | 4 + .../SeedBytesUpload/Service/ServiceClient.cs | 8 - .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Ast/Types/ContainerValue.cs | 8 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Ast/Types/ContainerValue.cs | 8 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/client-side-params/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedClientSideParams/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedClientSideParams/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedClientSideParams.csproj | 4 + seed/csharp-sdk/content-type/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedContentTypes/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedContentTypes/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedContentTypes/SeedContentTypes.csproj | 4 + .../cross-package-type-names/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedCrossPackageTypeNames.csproj | 4 + .../csharp-global-header-env/README.md | 11 +- .../csharp-global-header-env/snippet.json | 2 +- .../Unit/MockServer/BaseMockServerTest.cs | 2 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedCsharpGlobalHeaderEnv.csproj | 4 + .../.fern/metadata.json | 2 +- .../README.md | 11 +- .../snippet.json | 2 +- .../Unit/MockServer/BaseMockServerTest.cs | 2 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/Public/ClientOptions.cs | 1 + .../Core/QueryStringBuilder.cs | 2 +- .../SeedCsharpGlobalHeaderLiteralEnv.csproj | 4 + .../SeedCsharpGlobalHeaderLiteralEnvClient.cs | 1 + .../include-exception-handler/README.md | 7 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../no-custom-config/README.md | 7 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../package-id/README.md | 7 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../package-id/src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../package-id/src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../package-id/src/SeedApi/SeedApi.csproj | 4 + .../read-only-memory/README.md | 7 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../no-custom-config/README.md | 7 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../inline-types/README.md | 9 +- .../SeedObject.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedObject/Core/Extensions.cs | 2 + .../src/SeedObject/Core/NullableAttribute.cs | 8 +- .../src/SeedObject/Core/Optional.cs | 8 +- .../src/SeedObject/Core/OptionalAttribute.cs | 12 +- .../src/SeedObject/Core/QueryStringBuilder.cs | 2 +- .../src/SeedObject/SeedObject.csproj | 4 + .../Types/UnionTypeWithAliasListVariant.cs | 4 +- .../Types/UnionTypeWithAliasMapVariant.cs | 4 +- .../Types/UnionTypeWithAliasSetVariant.cs | 4 +- .../no-custom-config/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../explicit-namespaces/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/Contoso.Net/Contoso.Net.csproj | 4 + .../src/Contoso.Net/Core/Extensions.cs | 2 + .../src/Contoso.Net/Core/NullableAttribute.cs | 8 +- .../src/Contoso.Net/Core/Optional.cs | 8 +- .../src/Contoso.Net/Core/OptionalAttribute.cs | 12 +- .../Contoso.Net/Core/QueryStringBuilder.cs | 2 +- .../fully-qualified-namespaces/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedCsharpNamespaceCollision.csproj | 4 + .../namespace-client-collision/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/Contoso.Net/Contoso.Net.csproj | 4 + .../src/Contoso.Net/Core/Extensions.cs | 2 + .../src/Contoso.Net/Core/NullableAttribute.cs | 8 +- .../src/Contoso.Net/Core/Optional.cs | 8 +- .../src/Contoso.Net/Core/OptionalAttribute.cs | 12 +- .../Contoso.Net/Core/QueryStringBuilder.cs | 2 +- .../no-client-namespace-match/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/Contoso.Net/Contoso.Net.csproj | 4 + .../src/Contoso.Net/Core/Extensions.cs | 2 + .../src/Contoso.Net/Core/NullableAttribute.cs | 8 +- .../src/Contoso.Net/Core/Optional.cs | 8 +- .../src/Contoso.Net/Core/OptionalAttribute.cs | 12 +- .../Contoso.Net/Core/QueryStringBuilder.cs | 2 +- .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../Seed.CsharpNamespaceConflict.csproj | 4 + .../csharp-oauth-token-optional/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedCsharpOauthTokenOptional.csproj | 4 + .../no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedCsharpPathParamOrder/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedCsharpPathParamOrder.csproj | 4 + .../no-custom-config/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../csharp-readonly-request/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedCsharpReadonlyRequest.csproj | 4 + .../system-client/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedCsharpSystemCollision.csproj | 4 + .../dedupe-union-base-properties/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedCsharpUnionBaseProperties.csproj | 4 + .../no-custom-config/README.md | 9 +- .../Unit/MockServer/GetTimeZoneTest.cs | 4 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedCsharpXmlEntities/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedCsharpXmlEntities/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedCsharpXmlEntities.csproj | 4 + .../Types/TimeZoneModel.cs | 12 + .../no-documentation-file/.editorconfig | 35 + .../no-documentation-file/.fern/metadata.json | 12 + .../.github/workflows/ci.yml | 51 + .../no-documentation-file/.gitignore | 484 +++++++ .../no-documentation-file/CONTRIBUTING.md | 119 ++ .../no-documentation-file/README.md | 213 ++++ .../SeedCsharpXmlEntities.slnx | 4 + .../Snippets/Example0.cs | 15 + .../Snippets/Snippets.csproj | 11 + .../no-documentation-file/reference.md | 40 + .../no-documentation-file/snippet.json | 17 + .../Core/HeadersBuilderTests.cs | 326 +++++ .../Core/Json/AdditionalPropertiesTests.cs | 365 ++++++ .../Core/Json/DateOnlyJsonTests.cs | 100 ++ .../Core/Json/DateTimeJsonTests.cs | 134 ++ .../Core/Json/JsonAccessAttributeTests.cs | 160 +++ .../Core/QueryStringBuilderTests.cs | 672 ++++++++++ .../Core/QueryStringConverterTests.cs | 158 +++ .../Core/RawClientTests/GzipResponseTests.cs | 104 ++ .../Core/RawClientTests/MultipartFormTests.cs | 1121 +++++++++++++++++ .../RawClientTests/QueryParameterTests.cs | 108 ++ .../Core/RawClientTests/RetriesTests.cs | 540 ++++++++ .../Core/WithRawResponseTests.cs | 269 ++++ .../SeedCsharpXmlEntities.Test.Custom.props | 6 + .../SeedCsharpXmlEntities.Test.csproj | 39 + .../SeedCsharpXmlEntities.Test/TestClient.cs | 6 + .../Unit/MockServer/BaseMockServerTest.cs | 37 + .../Unit/MockServer/GetTimeZoneTest.cs | 36 + .../Utils/AdditionalPropertiesComparer.cs | 219 ++++ .../Utils/JsonAssert.cs | 33 + .../Utils/JsonElementComparer.cs | 243 ++++ .../Utils/NUnitExtensions.cs | 32 + .../Utils/OneOfComparer.cs | 100 ++ .../Utils/OptionalComparer.cs | 104 ++ .../Utils/ReadOnlyMemoryComparer.cs | 87 ++ .../SeedCsharpXmlEntities/Core/ApiResponse.cs | 13 + .../SeedCsharpXmlEntities/Core/BaseRequest.cs | 67 + .../Core/CollectionItemSerializer.cs | 91 ++ .../SeedCsharpXmlEntities/Core/Constants.cs | 7 + .../Core/DateOnlyConverter.cs | 747 +++++++++++ .../Core/DateTimeSerializer.cs | 40 + .../Core/DefaultHttpClientFactory.cs | 25 + .../Core/EmptyRequest.cs | 11 + .../Core/EncodingCache.cs | 11 + .../SeedCsharpXmlEntities/Core/Extensions.cs | 57 + .../Core/FormUrlEncoder.cs | 33 + .../SeedCsharpXmlEntities/Core/HeaderValue.cs | 52 + .../src/SeedCsharpXmlEntities/Core/Headers.cs | 28 + .../Core/HeadersBuilder.cs | 197 +++ .../Core/HttpContentExtensions.cs | 20 + .../Core/HttpMethodExtensions.cs | 8 + .../Core/IIsRetryableContent.cs | 6 + .../Core/IRequestOptions.cs | 83 ++ .../Core/JsonAccessAttribute.cs | 15 + .../Core/JsonConfiguration.cs | 275 ++++ .../SeedCsharpXmlEntities/Core/JsonRequest.cs | 36 + .../Core/MultipartFormRequest.cs | 294 +++++ .../Core/NullableAttribute.cs | 18 + .../Core/OneOfSerializer.cs | 190 +++ .../SeedCsharpXmlEntities/Core/Optional.cs | 474 +++++++ .../Core/OptionalAttribute.cs | 17 + .../Core/Public/AdditionalProperties.cs | 353 ++++++ .../Core/Public/ClientOptions.cs | 84 ++ .../Core/Public/FileParameter.cs | 63 + .../Core/Public/RawResponse.cs | 24 + .../Core/Public/RequestOptions.cs | 86 ++ .../SeedCsharpXmlEntitiesApiException.cs | 28 + .../Public/SeedCsharpXmlEntitiesException.cs | 7 + .../Core/Public/Version.cs | 7 + .../Core/Public/WithRawResponse.cs | 18 + .../Core/Public/WithRawResponseStream.cs | 66 + .../Core/Public/WithRawResponseTask.cs | 187 +++ .../Core/QueryStringBuilder.cs | 656 ++++++++++ .../Core/QueryStringConverter.cs | 259 ++++ .../SeedCsharpXmlEntities/Core/RawClient.cs | 364 ++++++ .../SeedCsharpXmlEntities/Core/RawResponse.cs | 24 + .../Core/ResponseHeaders.cs | 108 ++ .../Core/StreamRequest.cs | 29 + .../SeedCsharpXmlEntities/Core/StringEnum.cs | 6 + .../Core/StringEnumExtensions.cs | 6 + .../Core/ValueConvert.cs | 115 ++ .../ISeedCsharpXmlEntitiesClient.cs | 12 + .../SeedCsharpXmlEntities.Custom.props | 20 + .../SeedCsharpXmlEntities.csproj | 70 + .../SeedCsharpXmlEntitiesClient.cs | 127 ++ .../Types/TimeZoneModel.cs | 65 + .../package-metadata/.editorconfig | 35 + .../package-metadata/.fern/metadata.json | 27 + .../package-metadata/.github/workflows/ci.yml | 51 + .../package-metadata/.gitignore | 484 +++++++ .../package-metadata/CONTRIBUTING.md | 119 ++ .../package-metadata/README.md | 213 ++++ .../SeedCsharpXmlEntities.slnx | 4 + .../package-metadata/Snippets/Example0.cs | 15 + .../package-metadata/Snippets/Snippets.csproj | 11 + .../package-metadata/reference.md | 40 + .../package-metadata/snippet.json | 17 + .../Core/HeadersBuilderTests.cs | 326 +++++ .../Core/Json/AdditionalPropertiesTests.cs | 365 ++++++ .../Core/Json/DateOnlyJsonTests.cs | 100 ++ .../Core/Json/DateTimeJsonTests.cs | 134 ++ .../Core/Json/JsonAccessAttributeTests.cs | 160 +++ .../Core/QueryStringBuilderTests.cs | 672 ++++++++++ .../Core/QueryStringConverterTests.cs | 158 +++ .../Core/RawClientTests/GzipResponseTests.cs | 104 ++ .../Core/RawClientTests/MultipartFormTests.cs | 1121 +++++++++++++++++ .../RawClientTests/QueryParameterTests.cs | 108 ++ .../Core/RawClientTests/RetriesTests.cs | 540 ++++++++ .../Core/WithRawResponseTests.cs | 269 ++++ .../SeedCsharpXmlEntities.Test.Custom.props | 6 + .../SeedCsharpXmlEntities.Test.csproj | 39 + .../SeedCsharpXmlEntities.Test/TestClient.cs | 6 + .../Unit/MockServer/BaseMockServerTest.cs | 37 + .../Unit/MockServer/GetTimeZoneTest.cs | 36 + .../Utils/AdditionalPropertiesComparer.cs | 219 ++++ .../Utils/JsonAssert.cs | 33 + .../Utils/JsonElementComparer.cs | 243 ++++ .../Utils/NUnitExtensions.cs | 32 + .../Utils/OneOfComparer.cs | 100 ++ .../Utils/OptionalComparer.cs | 104 ++ .../Utils/ReadOnlyMemoryComparer.cs | 87 ++ .../SeedCsharpXmlEntities/Core/ApiResponse.cs | 13 + .../SeedCsharpXmlEntities/Core/BaseRequest.cs | 67 + .../Core/CollectionItemSerializer.cs | 91 ++ .../SeedCsharpXmlEntities/Core/Constants.cs | 7 + .../Core/DateOnlyConverter.cs | 747 +++++++++++ .../Core/DateTimeSerializer.cs | 40 + .../Core/DefaultHttpClientFactory.cs | 25 + .../Core/EmptyRequest.cs | 11 + .../Core/EncodingCache.cs | 11 + .../SeedCsharpXmlEntities/Core/Extensions.cs | 57 + .../Core/FormUrlEncoder.cs | 33 + .../SeedCsharpXmlEntities/Core/HeaderValue.cs | 52 + .../src/SeedCsharpXmlEntities/Core/Headers.cs | 28 + .../Core/HeadersBuilder.cs | 197 +++ .../Core/HttpContentExtensions.cs | 20 + .../Core/HttpMethodExtensions.cs | 8 + .../Core/IIsRetryableContent.cs | 6 + .../Core/IRequestOptions.cs | 83 ++ .../Core/JsonAccessAttribute.cs | 15 + .../Core/JsonConfiguration.cs | 275 ++++ .../SeedCsharpXmlEntities/Core/JsonRequest.cs | 36 + .../Core/MultipartFormRequest.cs | 294 +++++ .../Core/NullableAttribute.cs | 18 + .../Core/OneOfSerializer.cs | 190 +++ .../SeedCsharpXmlEntities/Core/Optional.cs | 474 +++++++ .../Core/OptionalAttribute.cs | 17 + .../Core/Public/AdditionalProperties.cs | 353 ++++++ .../Core/Public/ClientOptions.cs | 84 ++ .../Core/Public/FileParameter.cs | 63 + .../Core/Public/RawResponse.cs | 24 + .../Core/Public/RequestOptions.cs | 86 ++ .../SeedCsharpXmlEntitiesApiException.cs | 28 + .../Public/SeedCsharpXmlEntitiesException.cs | 7 + .../Core/Public/Version.cs | 7 + .../Core/Public/WithRawResponse.cs | 18 + .../Core/Public/WithRawResponseStream.cs | 66 + .../Core/Public/WithRawResponseTask.cs | 187 +++ .../Core/QueryStringBuilder.cs | 656 ++++++++++ .../Core/QueryStringConverter.cs | 259 ++++ .../SeedCsharpXmlEntities/Core/RawClient.cs | 364 ++++++ .../SeedCsharpXmlEntities/Core/RawResponse.cs | 24 + .../Core/ResponseHeaders.cs | 108 ++ .../Core/StreamRequest.cs | 29 + .../SeedCsharpXmlEntities/Core/StringEnum.cs | 6 + .../Core/StringEnumExtensions.cs | 6 + .../Core/ValueConvert.cs | 115 ++ .../ISeedCsharpXmlEntitiesClient.cs | 12 + .../SeedCsharpXmlEntities.Custom.props | 20 + .../SeedCsharpXmlEntities.csproj | 82 ++ .../SeedCsharpXmlEntitiesClient.cs | 127 ++ .../Types/TimeZoneModel.cs | 65 + .../README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedDollarStringExamples/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedDollarStringExamples.csproj | 4 + .../Utils/OptionalComparer.cs | 2 +- .../src/SeedEmptyClients/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedEmptyClients/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedEmptyClients/SeedEmptyClients.csproj | 4 + .../endpoint-security-auth/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedEndpointSecurityAuth/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedEndpointSecurityAuth.csproj | 4 + .../enum/forward-compatible-enums/README.md | 9 +- .../SeedEnum.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedEnum/Core/Extensions.cs | 2 + .../src/SeedEnum/Core/NullableAttribute.cs | 8 +- .../src/SeedEnum/Core/Optional.cs | 8 +- .../src/SeedEnum/Core/OptionalAttribute.cs | 12 +- .../src/SeedEnum/Core/QueryStringBuilder.cs | 2 +- .../src/SeedEnum/SeedEnum.csproj | 4 + seed/csharp-sdk/enum/plain-enums/README.md | 9 +- .../SeedEnum.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedEnum/Core/Extensions.cs | 2 + .../src/SeedEnum/Core/NullableAttribute.cs | 8 +- .../plain-enums/src/SeedEnum/Core/Optional.cs | 8 +- .../src/SeedEnum/Core/OptionalAttribute.cs | 12 +- .../src/SeedEnum/Core/QueryStringBuilder.cs | 2 +- .../plain-enums/src/SeedEnum/SeedEnum.csproj | 4 + seed/csharp-sdk/error-property/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedErrorProperty/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedErrorProperty/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedErrorProperty.csproj | 4 + seed/csharp-sdk/errors/README.md | 9 +- .../SeedErrors.Test/Utils/OptionalComparer.cs | 2 +- .../errors/src/SeedErrors/Core/Extensions.cs | 2 + .../src/SeedErrors/Core/NullableAttribute.cs | 8 +- .../errors/src/SeedErrors/Core/Optional.cs | 8 +- .../src/SeedErrors/Core/OptionalAttribute.cs | 12 +- .../src/SeedErrors/Core/QueryStringBuilder.cs | 2 +- .../errors/src/SeedErrors/SeedErrors.csproj | 4 + .../examples/no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedExamples/Core/Extensions.cs | 2 + .../SeedExamples/Core/NullableAttribute.cs | 8 +- .../src/SeedExamples/Core/Optional.cs | 8 +- .../SeedExamples/Core/OptionalAttribute.cs | 12 +- .../SeedExamples/Core/QueryStringBuilder.cs | 2 +- .../src/SeedExamples/SeedExamples.csproj | 4 + .../src/SeedExamples/Service/ServiceClient.cs | 2 +- .../src/SeedExamples/Types/Types/Exception.cs | 4 +- .../examples/readme-config/README.md | 11 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedExamples/Core/Extensions.cs | 2 + .../SeedExamples/Core/NullableAttribute.cs | 8 +- .../src/SeedExamples/Core/Optional.cs | 8 +- .../SeedExamples/Core/OptionalAttribute.cs | 12 +- .../SeedExamples/Core/QueryStringBuilder.cs | 2 +- .../src/SeedExamples/SeedExamples.csproj | 4 + .../src/SeedExamples/Service/ServiceClient.cs | 2 +- .../src/SeedExamples/Types/Types/Exception.cs | 4 +- .../auto-generate-idempotency-key/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedExhaustive/Core/Extensions.cs | 2 + .../SeedExhaustive/Core/NullableAttribute.cs | 8 +- .../src/SeedExhaustive/Core/Optional.cs | 8 +- .../SeedExhaustive/Core/OptionalAttribute.cs | 12 +- .../SeedExhaustive/Core/QueryStringBuilder.cs | 2 +- .../Endpoints/Params/ParamsClient.cs | 6 - .../src/SeedExhaustive/SeedExhaustive.csproj | 4 + .../Types/Docs/Types/ObjectWithDocs.cs | 10 +- .../exhaustive/explicit-namespaces/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedExhaustive/Core/Extensions.cs | 2 + .../SeedExhaustive/Core/NullableAttribute.cs | 8 +- .../src/SeedExhaustive/Core/Optional.cs | 8 +- .../SeedExhaustive/Core/OptionalAttribute.cs | 12 +- .../SeedExhaustive/Core/QueryStringBuilder.cs | 2 +- .../Endpoints/Params/ParamsClient.cs | 6 - .../src/SeedExhaustive/SeedExhaustive.csproj | 4 + .../Types/Docs/Types/ObjectWithDocs.cs | 10 +- .../include-exception-handler/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedExhaustive/Core/Extensions.cs | 2 + .../SeedExhaustive/Core/NullableAttribute.cs | 8 +- .../src/SeedExhaustive/Core/Optional.cs | 8 +- .../SeedExhaustive/Core/OptionalAttribute.cs | 12 +- .../SeedExhaustive/Core/QueryStringBuilder.cs | 2 +- .../Endpoints/Params/ParamsClient.cs | 6 - .../src/SeedExhaustive/SeedExhaustive.csproj | 4 + .../Types/Docs/Types/ObjectWithDocs.cs | 10 +- .../no-generate-error-types/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedExhaustive/Core/Extensions.cs | 2 + .../SeedExhaustive/Core/NullableAttribute.cs | 8 +- .../src/SeedExhaustive/Core/Optional.cs | 8 +- .../SeedExhaustive/Core/OptionalAttribute.cs | 12 +- .../SeedExhaustive/Core/QueryStringBuilder.cs | 2 +- .../Endpoints/Params/ParamsClient.cs | 6 - .../src/SeedExhaustive/SeedExhaustive.csproj | 4 + .../Types/Docs/Types/ObjectWithDocs.cs | 10 +- .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedExhaustive/Core/Extensions.cs | 2 + .../SeedExhaustive/Core/NullableAttribute.cs | 8 +- .../src/SeedExhaustive/Core/Optional.cs | 8 +- .../SeedExhaustive/Core/OptionalAttribute.cs | 12 +- .../SeedExhaustive/Core/QueryStringBuilder.cs | 2 +- .../Endpoints/Params/ParamsClient.cs | 6 - .../src/SeedExhaustive/SeedExhaustive.csproj | 4 + .../Types/Docs/Types/ObjectWithDocs.cs | 10 +- .../exhaustive/oidc-token/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedExhaustive/Core/Extensions.cs | 2 + .../SeedExhaustive/Core/NullableAttribute.cs | 8 +- .../src/SeedExhaustive/Core/Optional.cs | 8 +- .../SeedExhaustive/Core/OptionalAttribute.cs | 12 +- .../SeedExhaustive/Core/QueryStringBuilder.cs | 2 +- .../Endpoints/Params/ParamsClient.cs | 6 - .../src/SeedExhaustive/SeedExhaustive.csproj | 4 + .../Types/Docs/Types/ObjectWithDocs.cs | 10 +- .../redact-response-body-on-error/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedExhaustive/Core/Extensions.cs | 2 + .../SeedExhaustive/Core/NullableAttribute.cs | 8 +- .../src/SeedExhaustive/Core/Optional.cs | 8 +- .../SeedExhaustive/Core/OptionalAttribute.cs | 12 +- .../SeedExhaustive/Core/QueryStringBuilder.cs | 2 +- .../Endpoints/Params/ParamsClient.cs | 6 - .../src/SeedExhaustive/SeedExhaustive.csproj | 4 + .../Types/Docs/Types/ObjectWithDocs.cs | 10 +- .../use-undiscriminated-unions/README.md | 9 +- .../src/SeedExhaustive/Core/Extensions.cs | 2 + .../SeedExhaustive/Core/NullableAttribute.cs | 8 +- .../src/SeedExhaustive/Core/Optional.cs | 8 +- .../SeedExhaustive/Core/OptionalAttribute.cs | 12 +- .../SeedExhaustive/Core/QueryStringBuilder.cs | 2 +- .../Endpoints/Params/ParamsClient.cs | 6 - .../src/SeedExhaustive/SeedExhaustive.csproj | 4 + .../Types/Docs/Types/ObjectWithDocs.cs | 10 +- .../Types/Union/Types/MixedType.cs | 12 +- seed/csharp-sdk/extends/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedExtends/Core/Extensions.cs | 2 + .../src/SeedExtends/Core/NullableAttribute.cs | 8 +- .../extends/src/SeedExtends/Core/Optional.cs | 8 +- .../src/SeedExtends/Core/OptionalAttribute.cs | 12 +- .../SeedExtends/Core/QueryStringBuilder.cs | 2 +- .../src/SeedExtends/SeedExtends.csproj | 4 + seed/csharp-sdk/extra-properties/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedExtraProperties/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedExtraProperties/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedExtraProperties.csproj | 4 + seed/csharp-sdk/file-download/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedFileDownload/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedFileDownload/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedFileDownload/SeedFileDownload.csproj | 4 + seed/csharp-sdk/file-upload-openapi/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/file-upload/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedFileUpload/Core/Extensions.cs | 2 + .../SeedFileUpload/Core/NullableAttribute.cs | 8 +- .../src/SeedFileUpload/Core/Optional.cs | 8 +- .../SeedFileUpload/Core/OptionalAttribute.cs | 12 +- .../SeedFileUpload/Core/QueryStringBuilder.cs | 2 +- .../src/SeedFileUpload/SeedFileUpload.csproj | 4 + seed/csharp-sdk/folders/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../folders/src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../folders/src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../folders/src/SeedApi/SeedApi.csproj | 4 + .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedHeaderTokenEnvironmentVariable.csproj | 4 + seed/csharp-sdk/header-auth/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedHeaderToken/Core/Extensions.cs | 2 + .../SeedHeaderToken/Core/NullableAttribute.cs | 8 +- .../src/SeedHeaderToken/Core/Optional.cs | 8 +- .../SeedHeaderToken/Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedHeaderToken/SeedHeaderToken.csproj | 4 + seed/csharp-sdk/http-head/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedHttpHead/Core/Extensions.cs | 2 + .../SeedHttpHead/Core/NullableAttribute.cs | 8 +- .../src/SeedHttpHead/Core/Optional.cs | 8 +- .../SeedHttpHead/Core/OptionalAttribute.cs | 12 +- .../SeedHttpHead/Core/QueryStringBuilder.cs | 2 +- .../src/SeedHttpHead/SeedHttpHead.csproj | 4 + .../auto-generate-idempotency-key/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedIdempotencyHeaders/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedIdempotencyHeaders/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedIdempotencyHeaders.csproj | 4 + .../no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedIdempotencyHeaders/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedIdempotencyHeaders/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedIdempotencyHeaders.csproj | 4 + .../.fern/metadata.json | 5 +- .../imdb/allow-user-agent-app-info/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../imdb/exception-class-names/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../imdb/exported-client-class-name/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../extra-dependencies-override/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../imdb/extra-dependencies/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../imdb/include-exception-handler/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../imdb/include-platform-headers/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../imdb/no-custom-config/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../imdb/omit-fern-headers/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../inferred-auth-explicit/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedInferredAuthExplicit/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedInferredAuthExplicit.csproj | 4 + .../inferred-auth-implicit-api-key/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedInferredAuthImplicitApiKey.csproj | 4 + .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedInferredAuthImplicitNoExpiry.csproj | 4 + .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedInferredAuthImplicit/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedInferredAuthImplicit.csproj | 4 + .../inferred-auth-implicit/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedInferredAuthImplicit/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedInferredAuthImplicit.csproj | 4 + .../inline-enum-type-name-override/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../license/custom-license/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedLicense/Core/Extensions.cs | 2 + .../src/SeedLicense/Core/NullableAttribute.cs | 8 +- .../src/SeedLicense/Core/Optional.cs | 8 +- .../src/SeedLicense/Core/OptionalAttribute.cs | 12 +- .../SeedLicense/Core/QueryStringBuilder.cs | 2 +- .../src/SeedLicense/SeedLicense.csproj | 4 + seed/csharp-sdk/license/mit-license/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedLicense/Core/Extensions.cs | 2 + .../src/SeedLicense/Core/NullableAttribute.cs | 8 +- .../src/SeedLicense/Core/Optional.cs | 8 +- .../src/SeedLicense/Core/OptionalAttribute.cs | 12 +- .../SeedLicense/Core/QueryStringBuilder.cs | 2 +- .../src/SeedLicense/SeedLicense.csproj | 4 + seed/csharp-sdk/literal-user-agent/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedLiteralUserAgent/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedLiteralUserAgent/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/Public/ClientOptions.cs | 1 + .../Core/QueryStringBuilder.cs | 2 +- .../SeedLiteralUserAgent.csproj | 4 + .../literal/no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedLiteral/Core/Extensions.cs | 2 + .../src/SeedLiteral/Core/NullableAttribute.cs | 8 +- .../src/SeedLiteral/Core/Optional.cs | 8 +- .../src/SeedLiteral/Core/OptionalAttribute.cs | 12 +- .../SeedLiteral/Core/Public/ClientOptions.cs | 2 + .../SeedLiteral/Core/QueryStringBuilder.cs | 2 +- .../src/SeedLiteral/SeedLiteral.csproj | 4 + .../literal/readonly-constants/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedLiteral/Core/Extensions.cs | 2 + .../src/SeedLiteral/Core/NullableAttribute.cs | 8 +- .../src/SeedLiteral/Core/Optional.cs | 8 +- .../src/SeedLiteral/Core/OptionalAttribute.cs | 12 +- .../SeedLiteral/Core/Public/ClientOptions.cs | 2 + .../SeedLiteral/Core/QueryStringBuilder.cs | 2 +- .../src/SeedLiteral/SeedLiteral.csproj | 4 + .../Utils/OptionalComparer.cs | 2 +- .../src/SeedLiteralsUnions/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedLiteralsUnions/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedLiteralsUnions.csproj | 4 + seed/csharp-sdk/mixed-case/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedMixedCase/Core/Extensions.cs | 2 + .../SeedMixedCase/Core/NullableAttribute.cs | 8 +- .../src/SeedMixedCase/Core/Optional.cs | 8 +- .../SeedMixedCase/Core/OptionalAttribute.cs | 12 +- .../SeedMixedCase/Core/QueryStringBuilder.cs | 2 +- .../src/SeedMixedCase/SeedMixedCase.csproj | 4 + .../csharp-sdk/mixed-file-directory/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedMixedFileDirectory/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedMixedFileDirectory/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedMixedFileDirectory.csproj | 4 + .../multi-content-type-examples/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/multi-line-docs/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedMultiLineDocs/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedMultiLineDocs/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedMultiLineDocs.csproj | 4 + .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedMultiUrlEnvironmentNoDefault.csproj | 4 + .../multi-url-environment-reference/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../environment-class-name/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedMultiUrlEnvironment/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedMultiUrlEnvironment.csproj | 4 + .../no-pascal-case-environments/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedMultiUrlEnvironment/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedMultiUrlEnvironment.csproj | 4 + .../multiple-request-bodies/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/no-content-response/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/no-environment/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedNoEnvironment/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedNoEnvironment/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedNoEnvironment.csproj | 4 + seed/csharp-sdk/no-retries/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedNoRetries/Core/Extensions.cs | 2 + .../SeedNoRetries/Core/NullableAttribute.cs | 8 +- .../src/SeedNoRetries/Core/Optional.cs | 8 +- .../SeedNoRetries/Core/OptionalAttribute.cs | 12 +- .../SeedNoRetries/Core/QueryStringBuilder.cs | 2 +- .../src/SeedNoRetries/SeedNoRetries.csproj | 4 + seed/csharp-sdk/null-type/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../null-type/src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../null-type/src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../null-type/src/SeedApi/SeedApi.csproj | 4 + .../nullable-allof-extends/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../explicit-nullable-optional/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedNullableOptional/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedNullableOptional/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedNullableOptional.csproj | 4 + .../no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedNullableOptional/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedNullableOptional/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedNullableOptional.csproj | 4 + .../nullable-request-body/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../explicit-nullable-optional/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedNullable/Core/Extensions.cs | 2 + .../SeedNullable/Core/NullableAttribute.cs | 8 +- .../src/SeedNullable/Core/Optional.cs | 8 +- .../SeedNullable/Core/OptionalAttribute.cs | 12 +- .../SeedNullable/Core/QueryStringBuilder.cs | 2 +- .../src/SeedNullable/Nullable/Types/Status.cs | 12 +- .../src/SeedNullable/SeedNullable.csproj | 4 + .../nullable/no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedNullable/Core/Extensions.cs | 2 + .../SeedNullable/Core/NullableAttribute.cs | 8 +- .../src/SeedNullable/Core/Optional.cs | 8 +- .../SeedNullable/Core/OptionalAttribute.cs | 12 +- .../SeedNullable/Core/QueryStringBuilder.cs | 2 +- .../src/SeedNullable/Nullable/Types/Status.cs | 12 +- .../src/SeedNullable/SeedNullable.csproj | 4 + .../oauth-client-credentials-custom/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedOauthClientCredentials.csproj | 4 + .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedOauthClientCredentialsDefault.csproj | 4 + .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- ...ientCredentialsEnvironmentVariables.csproj | 4 + .../no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- ...OauthClientCredentialsMandatoryAuth.csproj | 4 + .../unified-client-options/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- ...OauthClientCredentialsMandatoryAuth.csproj | 4 + .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedOauthClientCredentials.csproj | 4 + .../README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- ...SeedOauthClientCredentialsReference.csproj | 4 + .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- ...OauthClientCredentialsWithVariables.csproj | 4 + .../include-exception-handler/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedOauthClientCredentials.csproj | 4 + .../no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedOauthClientCredentials.csproj | 4 + seed/csharp-sdk/oauth-pkce/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedOauthPkce/Core/Extensions.cs | 2 + .../SeedOauthPkce/Core/NullableAttribute.cs | 8 +- .../src/SeedOauthPkce/Core/Optional.cs | 8 +- .../SeedOauthPkce/Core/OptionalAttribute.cs | 12 +- .../SeedOauthPkce/Core/QueryStringBuilder.cs | 2 +- .../src/SeedOauthPkce/SeedOauthPkce.csproj | 4 + .../SeedObject.Test/Utils/OptionalComparer.cs | 2 +- .../object/src/SeedObject/Core/Extensions.cs | 2 + .../src/SeedObject/Core/NullableAttribute.cs | 8 +- .../object/src/SeedObject/Core/Optional.cs | 8 +- .../src/SeedObject/Core/OptionalAttribute.cs | 12 +- .../src/SeedObject/Core/QueryStringBuilder.cs | 2 +- .../object/src/SeedObject/SeedObject.csproj | 4 + .../Utils/OptionalComparer.cs | 2 +- .../SeedObjectsWithImports/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedObjectsWithImports/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedObjectsWithImports.csproj | 4 + .../README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../openapi-request-body-ref/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/openapi-subtitle/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../optional/no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedObjectsWithImports/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedObjectsWithImports/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedObjectsWithImports.csproj | 4 + .../simplify-object-dictionaries/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedObjectsWithImports/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedObjectsWithImports/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedObjectsWithImports.csproj | 4 + seed/csharp-sdk/package-yml/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedPackageYml/Core/Extensions.cs | 2 + .../SeedPackageYml/Core/NullableAttribute.cs | 8 +- .../src/SeedPackageYml/Core/Optional.cs | 8 +- .../SeedPackageYml/Core/OptionalAttribute.cs | 12 +- .../SeedPackageYml/Core/QueryStringBuilder.cs | 2 +- .../src/SeedPackageYml/SeedPackageYml.csproj | 4 + seed/csharp-sdk/pagination-custom/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedPagination/Core/Extensions.cs | 2 + .../SeedPagination/Core/NullableAttribute.cs | 8 +- .../src/SeedPagination/Core/Optional.cs | 8 +- .../SeedPagination/Core/OptionalAttribute.cs | 12 +- .../SeedPagination/Core/QueryStringBuilder.cs | 2 +- .../src/SeedPagination/SeedPagination.csproj | 4 + seed/csharp-sdk/pagination-uri-path/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedPaginationUriPath/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedPaginationUriPath/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedPaginationUriPath.csproj | 4 + .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedPagination/Core/Extensions.cs | 2 + .../SeedPagination/Core/NullableAttribute.cs | 8 +- .../src/SeedPagination/Core/Optional.cs | 8 +- .../SeedPagination/Core/OptionalAttribute.cs | 12 +- .../SeedPagination/Core/QueryStringBuilder.cs | 2 +- .../src/SeedPagination/SeedPagination.csproj | 4 + .../pagination/custom-pager/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedPagination/Core/Extensions.cs | 2 + .../SeedPagination/Core/NullableAttribute.cs | 8 +- .../src/SeedPagination/Core/Optional.cs | 8 +- .../SeedPagination/Core/OptionalAttribute.cs | 12 +- .../SeedPagination/Core/QueryStringBuilder.cs | 2 +- .../src/SeedPagination/SeedPagination.csproj | 4 + .../pagination/no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedPagination/Core/Extensions.cs | 2 + .../SeedPagination/Core/NullableAttribute.cs | 8 +- .../src/SeedPagination/Core/Optional.cs | 8 +- .../SeedPagination/Core/OptionalAttribute.cs | 12 +- .../SeedPagination/Core/QueryStringBuilder.cs | 2 +- .../src/SeedPagination/SeedPagination.csproj | 4 + .../pagination/page-index-semantics/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedPagination/Core/Extensions.cs | 2 + .../SeedPagination/Core/NullableAttribute.cs | 8 +- .../src/SeedPagination/Core/Optional.cs | 8 +- .../SeedPagination/Core/OptionalAttribute.cs | 12 +- .../SeedPagination/Core/QueryStringBuilder.cs | 2 +- .../src/SeedPagination/SeedPagination.csproj | 4 + .../no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedPathParameters/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedPathParameters/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedPathParameters.csproj | 4 + .../no-inline-path-parameters/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedPathParameters/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedPathParameters/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedPathParameters.csproj | 4 + seed/csharp-sdk/plain-text/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedPlainText/Core/Extensions.cs | 2 + .../SeedPlainText/Core/NullableAttribute.cs | 8 +- .../src/SeedPlainText/Core/Optional.cs | 8 +- .../SeedPlainText/Core/OptionalAttribute.cs | 12 +- .../SeedPlainText/Core/QueryStringBuilder.cs | 2 +- .../src/SeedPlainText/SeedPlainText.csproj | 4 + seed/csharp-sdk/property-access/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedPropertyAccess/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedPropertyAccess/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedPropertyAccess.csproj | 4 + .../Types/UserOrAdminDiscriminated.cs | 4 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedPublicObject/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedPublicObject/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedPublicObject/SeedPublicObject.csproj | 4 + .../query-param-name-conflict/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../query-parameters-openapi/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/query-parameters/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedQueryParameters/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedQueryParameters/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedQueryParameters.csproj | 4 + .../no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedRequestParameters/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedRequestParameters/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedRequestParameters.csproj | 4 + .../with-defaults/README.md | 9 +- .../SeedRequestParameters/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedRequestParameters/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedRequestParameters.csproj | 4 + .../explicit-nullable-optional/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../no-custom-config/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/reserved-keywords/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedNurseryApi/Core/Extensions.cs | 2 + .../SeedNurseryApi/Core/NullableAttribute.cs | 8 +- .../src/SeedNurseryApi/Core/Optional.cs | 8 +- .../SeedNurseryApi/Core/OptionalAttribute.cs | 12 +- .../SeedNurseryApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedNurseryApi/SeedNurseryApi.csproj | 4 + .../no-custom-config/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../respect-optional-request-body/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/response-property/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedResponseProperty/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedResponseProperty/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedResponseProperty.csproj | 4 + .../README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/seed.yml | 18 + .../server-sent-event-examples/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedServerSentEvents/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedServerSentEvents/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedServerSentEvents.csproj | 4 + .../server-sent-events-openapi/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../server-sent-events-resumable/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedServerSentEventsResumable.csproj | 4 + seed/csharp-sdk/server-sent-events/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedServerSentEvents/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedServerSentEvents/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedServerSentEvents.csproj | 4 + .../disable-server-url-variables/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../no-custom-config/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../disable-server-url-variables/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../no-custom-config/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../lib/SeedApi/README.md | 9 +- .../SeedApi/SeedSimpleApi/Core/Extensions.cs | 2 + .../SeedSimpleApi/Core/NullableAttribute.cs | 8 +- .../SeedApi/SeedSimpleApi/Core/Optional.cs | 8 +- .../SeedSimpleApi/Core/OptionalAttribute.cs | 12 +- .../SeedSimpleApi/Core/QueryStringBuilder.cs | 2 +- .../SeedSimpleApi/SeedSimpleApi.csproj | 4 + .../Utils/OptionalComparer.cs | 2 +- .../simple-api/custom-output-path/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../SeedSimpleApi/Core/Extensions.cs | 2 + .../SeedSimpleApi/Core/NullableAttribute.cs | 8 +- .../custom-src/SeedSimpleApi/Core/Optional.cs | 8 +- .../SeedSimpleApi/Core/OptionalAttribute.cs | 12 +- .../SeedSimpleApi/Core/QueryStringBuilder.cs | 2 +- .../SeedSimpleApi/SeedSimpleApi.csproj | 4 + .../simple-api/no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedSimpleApi/Core/Extensions.cs | 2 + .../SeedSimpleApi/Core/NullableAttribute.cs | 8 +- .../src/SeedSimpleApi/Core/Optional.cs | 8 +- .../SeedSimpleApi/Core/OptionalAttribute.cs | 12 +- .../SeedSimpleApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedSimpleApi/SeedSimpleApi.csproj | 4 + .../simple-api/use-sln-format/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedSimpleApi/Core/Extensions.cs | 2 + .../SeedSimpleApi/Core/NullableAttribute.cs | 8 +- .../src/SeedSimpleApi/Core/Optional.cs | 8 +- .../SeedSimpleApi/Core/OptionalAttribute.cs | 12 +- .../SeedSimpleApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedSimpleApi/SeedSimpleApi.csproj | 4 + seed/csharp-sdk/simple-fhir/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../simple-fhir/src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../simple-fhir/src/SeedApi/SeedApi.csproj | 4 + .../single-url-environment-default/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedSingleUrlEnvironmentDefault.csproj | 4 + .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedSingleUrlEnvironmentNoDefault.csproj | 4 + seed/csharp-sdk/streaming-parameter/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedStreaming/Core/Extensions.cs | 2 + .../SeedStreaming/Core/NullableAttribute.cs | 8 +- .../src/SeedStreaming/Core/Optional.cs | 8 +- .../SeedStreaming/Core/OptionalAttribute.cs | 12 +- .../SeedStreaming/Core/QueryStringBuilder.cs | 2 +- .../src/SeedStreaming/SeedStreaming.csproj | 4 + .../streaming/no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedStreaming/Core/Extensions.cs | 2 + .../SeedStreaming/Core/NullableAttribute.cs | 8 +- .../src/SeedStreaming/Core/Optional.cs | 8 +- .../SeedStreaming/Core/OptionalAttribute.cs | 12 +- .../SeedStreaming/Core/QueryStringBuilder.cs | 2 +- .../src/SeedStreaming/SeedStreaming.csproj | 4 + .../redact-response-body-on-error/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedStreaming/Core/Extensions.cs | 2 + .../SeedStreaming/Core/NullableAttribute.cs | 8 +- .../src/SeedStreaming/Core/Optional.cs | 8 +- .../SeedStreaming/Core/OptionalAttribute.cs | 12 +- .../SeedStreaming/Core/QueryStringBuilder.cs | 2 +- .../src/SeedStreaming/SeedStreaming.csproj | 4 + seed/csharp-sdk/trace/README.md | 9 +- .../SeedTrace.Test/Utils/OptionalComparer.cs | 2 +- .../Commons/Types/DebugVariableValue.cs | 12 +- .../SeedTrace/Commons/Types/VariableType.cs | 32 +- .../SeedTrace/Commons/Types/VariableValue.cs | 8 +- .../trace/src/SeedTrace/Core/Extensions.cs | 2 + .../src/SeedTrace/Core/NullableAttribute.cs | 8 +- .../trace/src/SeedTrace/Core/Optional.cs | 8 +- .../src/SeedTrace/Core/OptionalAttribute.cs | 12 +- .../src/SeedTrace/Core/QueryStringBuilder.cs | 2 +- .../trace/src/SeedTrace/SeedTrace.csproj | 4 + .../SeedTrace/Submission/Types/ExceptionV2.cs | 4 +- .../Submission/Types/SubmissionRequest.cs | 4 +- .../Submission/Types/SubmissionResponse.cs | 8 +- .../Submission/Types/TestSubmissionStatus.cs | 8 +- .../Types/TestSubmissionUpdateInfo.cs | 8 +- .../Types/WorkspaceSubmissionStatus.cs | 4 +- .../Types/WorkspaceSubmissionUpdateInfo.cs | 12 +- .../SeedTrace/V2/Problem/Types/CustomFiles.cs | 4 +- .../V2/V3/Problem/Types/CustomFiles.cs | 4 +- .../README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- ...criminatedUnionWithResponseProperty.csproj | 4 + .../no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedUndiscriminatedUnions.csproj | 4 + .../with-undiscriminated-unions/README.md | 9 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedUndiscriminatedUnions.csproj | 4 + .../Union/Types/AliasedObjectUnion.cs | 4 +- .../Union/Types/Key.cs | 2 +- .../Union/Types/MetadataUnion.cs | 8 +- .../Union/Types/MyUnion.cs | 28 +- .../Union/Types/NestedObjectUnion.cs | 4 +- .../Union/Types/NestedUnionL1.cs | 16 +- .../Union/Types/NestedUnionL2.cs | 14 +- .../Union/Types/NestedUnionRoot.cs | 10 +- .../Union/Types/OuterNestedUnion.cs | 4 +- .../Union/Types/PaymentMethodUnion.cs | 4 +- .../Union/Types/UnionWithBaseProperties.cs | 8 +- .../Union/Types/UnionWithDuplicateTypes.cs | 16 +- .../Types/UnionWithIdenticalPrimitives.cs | 6 +- .../Union/Types/UnionWithIdenticalStrings.cs | 2 +- .../Union/Types/UnionWithReservedNames.cs | 2 +- .../Union/Types/UnionWithTypeAliases.cs | 6 +- .../union-query-parameters/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedUnionQueryParameters/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedUnionQueryParameters.csproj | 4 + .../unions-with-local-date/README.md | 9 +- .../SeedUnions.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedUnions/Core/Extensions.cs | 2 + .../src/SeedUnions/Core/NullableAttribute.cs | 8 +- .../src/SeedUnions/Core/Optional.cs | 8 +- .../src/SeedUnions/Core/OptionalAttribute.cs | 12 +- .../src/SeedUnions/Core/QueryStringBuilder.cs | 2 +- .../src/SeedUnions/SeedUnions.csproj | 4 + .../Types/UnionWithMultipleNoProperties.cs | 8 +- .../Types/Types/UnionWithNoProperties.cs | 4 +- .../Types/Types/UnionWithOptionalTime.cs | 8 +- .../unions/no-custom-config/README.md | 9 +- .../SeedUnions.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedUnions/Core/Extensions.cs | 2 + .../src/SeedUnions/Core/NullableAttribute.cs | 8 +- .../src/SeedUnions/Core/Optional.cs | 8 +- .../src/SeedUnions/Core/OptionalAttribute.cs | 12 +- .../src/SeedUnions/Core/QueryStringBuilder.cs | 2 +- .../src/SeedUnions/SeedUnions.csproj | 4 + .../Types/UnionWithMultipleNoProperties.cs | 8 +- .../Types/Types/UnionWithNoProperties.cs | 4 +- .../Types/Types/UnionWithNullableReference.cs | 8 +- .../Types/Types/UnionWithOptionalReference.cs | 8 +- .../Types/Types/UnionWithOptionalTime.cs | 8 +- .../unions/no-discriminated-unions/README.md | 9 +- .../SeedUnions.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedUnions/Core/Extensions.cs | 2 + .../src/SeedUnions/Core/NullableAttribute.cs | 8 +- .../src/SeedUnions/Core/Optional.cs | 8 +- .../src/SeedUnions/Core/OptionalAttribute.cs | 12 +- .../src/SeedUnions/Core/QueryStringBuilder.cs | 2 +- .../src/SeedUnions/SeedUnions.csproj | 4 + seed/csharp-sdk/unknown/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedUnknownAsAny/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedUnknownAsAny/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedUnknownAsAny/SeedUnknownAsAny.csproj | 4 + .../no-custom-config/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + seed/csharp-sdk/validation/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedValidation/Core/Extensions.cs | 2 + .../SeedValidation/Core/NullableAttribute.cs | 8 +- .../src/SeedValidation/Core/Optional.cs | 8 +- .../SeedValidation/Core/OptionalAttribute.cs | 12 +- .../SeedValidation/Core/QueryStringBuilder.cs | 2 +- .../src/SeedValidation/SeedValidation.csproj | 4 + seed/csharp-sdk/variables/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedVariables/Core/Extensions.cs | 2 + .../SeedVariables/Core/NullableAttribute.cs | 8 +- .../src/SeedVariables/Core/Optional.cs | 8 +- .../SeedVariables/Core/OptionalAttribute.cs | 12 +- .../SeedVariables/Core/QueryStringBuilder.cs | 2 +- .../src/SeedVariables/SeedVariables.csproj | 4 + seed/csharp-sdk/version-no-default/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedVersion/Core/Extensions.cs | 2 + .../src/SeedVersion/Core/NullableAttribute.cs | 8 +- .../src/SeedVersion/Core/Optional.cs | 8 +- .../src/SeedVersion/Core/OptionalAttribute.cs | 12 +- .../SeedVersion/Core/QueryStringBuilder.cs | 2 +- .../src/SeedVersion/SeedVersion.csproj | 4 + seed/csharp-sdk/version/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedVersion/Core/Extensions.cs | 2 + .../src/SeedVersion/Core/NullableAttribute.cs | 8 +- .../version/src/SeedVersion/Core/Optional.cs | 8 +- .../src/SeedVersion/Core/OptionalAttribute.cs | 12 +- .../SeedVersion/Core/QueryStringBuilder.cs | 2 +- .../src/SeedVersion/SeedVersion.csproj | 4 + .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../Utils/OptionalComparer.cs | 2 +- .../src/SeedWebhooks/Core/Extensions.cs | 2 + .../SeedWebhooks/Core/NullableAttribute.cs | 8 +- .../src/SeedWebhooks/Core/Optional.cs | 8 +- .../SeedWebhooks/Core/OptionalAttribute.cs | 12 +- .../SeedWebhooks/Core/QueryStringBuilder.cs | 2 +- .../src/SeedWebhooks/SeedWebhooks.csproj | 4 + .../Utils/OptionalComparer.cs | 2 +- .../Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedWebsocketBearerAuth/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedWebsocketBearerAuth.csproj | 4 + .../websocket-inferred-auth/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedWebsocketAuth/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../src/SeedWebsocketAuth/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../SeedWebsocketAuth.csproj | 4 + .../Utils/OptionalComparer.cs | 2 +- .../SeedWebsocketMultiUrl/Core/Extensions.cs | 2 + .../Core/NullableAttribute.cs | 8 +- .../SeedWebsocketMultiUrl/Core/Optional.cs | 8 +- .../Core/OptionalAttribute.cs | 12 +- .../Core/QueryStringBuilder.cs | 2 +- .../Core/WebSockets/Query.cs | 2 +- .../Core/WebSockets/WebSocketClient.cs | 4 + .../SeedWebsocketMultiUrl.csproj | 4 + .../websocket/no-custom-config/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedWebsocket/Core/Extensions.cs | 2 + .../SeedWebsocket/Core/NullableAttribute.cs | 8 +- .../src/SeedWebsocket/Core/Optional.cs | 8 +- .../SeedWebsocket/Core/OptionalAttribute.cs | 12 +- .../SeedWebsocket/Core/QueryStringBuilder.cs | 2 +- .../src/SeedWebsocket/SeedWebsocket.csproj | 4 + .../websocket/with-websockets/README.md | 9 +- .../Utils/OptionalComparer.cs | 2 +- .../src/SeedWebsocket/Core/Extensions.cs | 2 + .../SeedWebsocket/Core/NullableAttribute.cs | 8 +- .../src/SeedWebsocket/Core/Optional.cs | 8 +- .../SeedWebsocket/Core/OptionalAttribute.cs | 12 +- .../SeedWebsocket/Core/QueryStringBuilder.cs | 2 +- .../SeedWebsocket/Core/WebSockets/Query.cs | 2 +- .../Core/WebSockets/WebSocketClient.cs | 4 + .../src/SeedWebsocket/SeedWebsocket.csproj | 4 + seed/csharp-sdk/x-fern-default/README.md | 11 +- seed/csharp-sdk/x-fern-default/snippet.json | 2 +- .../Unit/MockServer/BaseMockServerTest.cs | 2 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../x-fern-default/src/SeedApi/SeedApi.csproj | 4 + .../x-fern-global-parameters/README.md | 9 +- .../SeedApi.Test/Utils/OptionalComparer.cs | 2 +- .../src/SeedApi/Core/Extensions.cs | 2 + .../src/SeedApi/Core/NullableAttribute.cs | 8 +- .../src/SeedApi/Core/Optional.cs | 8 +- .../src/SeedApi/Core/OptionalAttribute.cs | 12 +- .../src/SeedApi/Core/QueryStringBuilder.cs | 2 +- .../src/SeedApi/SeedApi.csproj | 4 + .../definition/__package__.yml | 6 + .../fern/apis/csharp-xml-entities/openapi.yml | 8 + 1881 files changed, 29998 insertions(+), 4112 deletions(-) create mode 100644 generators/csharp/base/src/project/__test__/targetFrameworks.test.ts create mode 100644 generators/csharp/base/src/project/targetFrameworks.ts create mode 100644 generators/csharp/sdk/changes/unreleased/feat-docs-and-package-metadata.yml create mode 100644 generators/csharp/sdk/changes/unreleased/fix-client-options-global-headers.yml create mode 100644 generators/csharp/sdk/changes/unreleased/fix-doc-comment-attribute-escaping.yml create mode 100644 generators/csharp/sdk/changes/unreleased/fix-readme-requirements.yml create mode 100644 generators/csharp/sdk/changes/unreleased/fix-readme-snippets.yml create mode 100644 generators/csharp/sdk/changes/unreleased/fix-union-cref-doc-comments.yml create mode 100644 generators/csharp/sdk/changes/unreleased/fix-xml-doc-comments.yml create mode 100644 packages/generator-cli/changes/unreleased/fix-empty-readme-requirements.yml create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.editorconfig create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.fern/metadata.json create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.github/workflows/ci.yml create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.gitignore create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/CONTRIBUTING.md create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/README.md create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/SeedCsharpXmlEntities.slnx create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/Snippets/Example0.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/Snippets/Snippets.csproj create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/reference.md create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/snippet.json create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/HeadersBuilderTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/AdditionalPropertiesTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/DateOnlyJsonTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/DateTimeJsonTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/JsonAccessAttributeTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/QueryStringBuilderTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/QueryStringConverterTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/GzipResponseTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/MultipartFormTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/QueryParameterTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/RetriesTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/WithRawResponseTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.Custom.props create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/TestClient.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Unit/MockServer/BaseMockServerTest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Unit/MockServer/GetTimeZoneTest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/AdditionalPropertiesComparer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/JsonAssert.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/JsonElementComparer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/NUnitExtensions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/OneOfComparer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/OptionalComparer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/ReadOnlyMemoryComparer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/ApiResponse.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/BaseRequest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/CollectionItemSerializer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Constants.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/DateOnlyConverter.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/DateTimeSerializer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/DefaultHttpClientFactory.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/EmptyRequest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/EncodingCache.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Extensions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/FormUrlEncoder.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HeaderValue.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Headers.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HeadersBuilder.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HttpContentExtensions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HttpMethodExtensions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/IIsRetryableContent.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/IRequestOptions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/JsonAccessAttribute.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/JsonConfiguration.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/JsonRequest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/MultipartFormRequest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/NullableAttribute.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/OneOfSerializer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Optional.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/OptionalAttribute.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/AdditionalProperties.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/ClientOptions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/FileParameter.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/RawResponse.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/RequestOptions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesApiException.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesException.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/Version.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/WithRawResponse.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseStream.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseTask.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/QueryStringBuilder.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/QueryStringConverter.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/RawClient.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/RawResponse.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/ResponseHeaders.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/StreamRequest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/StringEnum.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/StringEnumExtensions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/ValueConvert.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/ISeedCsharpXmlEntitiesClient.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.Custom.props create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/SeedCsharpXmlEntitiesClient.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Types/TimeZoneModel.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/.editorconfig create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/.fern/metadata.json create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/.github/workflows/ci.yml create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/.gitignore create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/CONTRIBUTING.md create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/README.md create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/SeedCsharpXmlEntities.slnx create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/Snippets/Example0.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/Snippets/Snippets.csproj create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/reference.md create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/snippet.json create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/HeadersBuilderTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/AdditionalPropertiesTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/DateOnlyJsonTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/DateTimeJsonTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/JsonAccessAttributeTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/QueryStringBuilderTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/QueryStringConverterTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/GzipResponseTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/MultipartFormTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/QueryParameterTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/RetriesTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/WithRawResponseTests.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.Custom.props create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/TestClient.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Unit/MockServer/BaseMockServerTest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Unit/MockServer/GetTimeZoneTest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/AdditionalPropertiesComparer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/JsonAssert.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/JsonElementComparer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/NUnitExtensions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/OneOfComparer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/OptionalComparer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/ReadOnlyMemoryComparer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/ApiResponse.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/BaseRequest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/CollectionItemSerializer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Constants.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/DateOnlyConverter.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/DateTimeSerializer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/DefaultHttpClientFactory.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/EmptyRequest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/EncodingCache.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Extensions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/FormUrlEncoder.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HeaderValue.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Headers.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HeadersBuilder.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HttpContentExtensions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HttpMethodExtensions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/IIsRetryableContent.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/IRequestOptions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/JsonAccessAttribute.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/JsonConfiguration.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/JsonRequest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/MultipartFormRequest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/NullableAttribute.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/OneOfSerializer.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Optional.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/OptionalAttribute.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/AdditionalProperties.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/ClientOptions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/FileParameter.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/RawResponse.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/RequestOptions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesApiException.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesException.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/Version.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/WithRawResponse.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseStream.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseTask.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/QueryStringBuilder.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/QueryStringConverter.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/RawClient.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/RawResponse.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/ResponseHeaders.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/StreamRequest.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/StringEnum.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/StringEnumExtensions.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/ValueConvert.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/ISeedCsharpXmlEntitiesClient.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.Custom.props create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/SeedCsharpXmlEntitiesClient.cs create mode 100644 seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Types/TimeZoneModel.cs diff --git a/generators/csharp/base/src/asIs/Extensions.cs b/generators/csharp/base/src/asIs/Extensions.cs index c94625b493f4..d6724096284f 100644 --- a/generators/csharp/base/src/asIs/Extensions.cs +++ b/generators/csharp/base/src/asIs/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/generators/csharp/base/src/asIs/NullableAttribute.Template.cs b/generators/csharp/base/src/asIs/NullableAttribute.Template.cs index 35ecafbc5793..4afc7b88c51d 100644 --- a/generators/csharp/base/src/asIs/NullableAttribute.Template.cs +++ b/generators/csharp/base/src/asIs/NullableAttribute.Template.cs @@ -2,7 +2,7 @@ namespace <%= namespace%>; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace <%= namespace%>; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute diff --git a/generators/csharp/base/src/asIs/Optional.Template.cs b/generators/csharp/base/src/asIs/Optional.Template.cs index 02ad860743aa..db7c56cae462 100644 --- a/generators/csharp/base/src/asIs/Optional.Template.cs +++ b/generators/csharp/base/src/asIs/Optional.Template.cs @@ -267,7 +267,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -345,7 +345,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -400,7 +400,7 @@ string key /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -425,7 +425,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/generators/csharp/base/src/asIs/OptionalAttribute.Template.cs b/generators/csharp/base/src/asIs/OptionalAttribute.Template.cs index 9742cde0d509..ab5ca0780c05 100644 --- a/generators/csharp/base/src/asIs/OptionalAttribute.Template.cs +++ b/generators/csharp/base/src/asIs/OptionalAttribute.Template.cs @@ -2,16 +2,16 @@ namespace <%= namespace%>; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute diff --git a/generators/csharp/base/src/asIs/QueryStringBuilder.Template.cs b/generators/csharp/base/src/asIs/QueryStringBuilder.Template.cs index 1138359bf1ec..46672015ca6a 100644 --- a/generators/csharp/base/src/asIs/QueryStringBuilder.Template.cs +++ b/generators/csharp/base/src/asIs/QueryStringBuilder.Template.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/generators/csharp/base/src/asIs/WebSockets/Query.Template.cs b/generators/csharp/base/src/asIs/WebSockets/Query.Template.cs index b0455e690ded..2321f1c2be75 100644 --- a/generators/csharp/base/src/asIs/WebSockets/Query.Template.cs +++ b/generators/csharp/base/src/asIs/WebSockets/Query.Template.cs @@ -122,7 +122,7 @@ public void Add(string key, Object? value) /// /// Converts the query parameters to a URL-encoded query string. /// - /// A string representation of the query parameters in the format "key1=value1&key2=value2". + /// A string representation of the query parameters in the format "key1=value1&key2=value2". public override string ToString() { return string.Join( diff --git a/generators/csharp/base/src/asIs/WebSockets/WebSocketClient.Template.cs b/generators/csharp/base/src/asIs/WebSockets/WebSocketClient.Template.cs index 82206fc653f3..f7fc8582943d 100644 --- a/generators/csharp/base/src/asIs/WebSockets/WebSocketClient.Template.cs +++ b/generators/csharp/base/src/asIs/WebSockets/WebSocketClient.Template.cs @@ -134,6 +134,7 @@ private void EnsureConnected() /// Sends a text message instantly through the WebSocket connection. /// /// The text message to send. + /// Token to cancel the send operation. /// A task representing the asynchronous send operation. /// Thrown when the connection is not in Connected status. public global::System.Threading.Tasks.Task SendInstant(string message, CancellationToken cancellationToken = default) @@ -146,6 +147,7 @@ private void EnsureConnected() /// Sends a binary message instantly through the WebSocket connection. /// /// The binary message to send as a Memory<byte>. + /// Token to cancel the send operation. /// A task representing the asynchronous send operation. /// Thrown when the connection is not in Connected status. public global::System.Threading.Tasks.Task SendInstant(Memory message, CancellationToken cancellationToken = default) @@ -158,6 +160,7 @@ private void EnsureConnected() /// Sends a binary message instantly through the WebSocket connection. /// /// The binary message to send as an ArraySegment<byte>. + /// Token to cancel the send operation. /// A task representing the asynchronous send operation. /// Thrown when the connection is not in Connected status. public global::System.Threading.Tasks.Task SendInstant(ArraySegment message, CancellationToken cancellationToken = default) @@ -170,6 +173,7 @@ private void EnsureConnected() /// Sends a binary message instantly through the WebSocket connection. /// /// The binary message to send as a byte array. + /// Token to cancel the send operation. /// A task representing the asynchronous send operation. /// Thrown when the connection is not in Connected status. public global::System.Threading.Tasks.Task SendInstant(byte[] message, CancellationToken cancellationToken = default) diff --git a/generators/csharp/base/src/asIs/test/Utils/OptionalComparer.Template.cs b/generators/csharp/base/src/asIs/test/Utils/OptionalComparer.Template.cs index 5cc26a39e527..f29f9af2b6c4 100644 --- a/generators/csharp/base/src/asIs/test/Utils/OptionalComparer.Template.cs +++ b/generators/csharp/base/src/asIs/test/Utils/OptionalComparer.Template.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/generators/csharp/base/src/project/CsharpProject.ts b/generators/csharp/base/src/project/CsharpProject.ts index 44ecaeff64f0..2de47de09127 100644 --- a/generators/csharp/base/src/project/CsharpProject.ts +++ b/generators/csharp/base/src/project/CsharpProject.ts @@ -10,6 +10,7 @@ import { AsIsFiles } from "../AsIs.js"; import { GeneratorContext } from "../context/GeneratorContext.js"; import { findDotnetToolPath } from "../findDotNetToolPath.js"; import { CSharpFile } from "./CSharpFile.js"; +import { TARGET_FRAMEWORKS } from "./targetFrameworks.js"; const eta = new Eta({ autoEscape: false, useWith: true, autoTrim: false }); @@ -822,6 +823,21 @@ function generateDeterministicGuid(name: string): string { return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20, 32)}`.toUpperCase(); } +/** + * Joins a metadata value that may be a single string or a list into the + * delimiter-separated form MSBuild expects. Returns undefined when unset. + */ +function joinMetadataList(value: string | string[] | undefined, delimiter: string): string | undefined { + if (value == null) { + return undefined; + } + return Array.isArray(value) ? value.join(delimiter) : value; +} + +function escapeXml(value: string): string { + return value.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); +} + declare namespace CsProj { interface Args { name: string; @@ -969,6 +985,13 @@ ${this.getAdditionalItemGroups().join(`\n${indent}`)} '' ); } + if (this.generation.settings.packageMetadata["include-source-link"]) { + pushIfNotOverridden( + result, + SOURCE_LINK_PACKAGE.name, + `` + ); + } for (const [name, version] of Object.entries(extraDeps)) { // PolySharp is already handled above with its required metadata. if (name.toLowerCase() === "polysharp") { @@ -1084,7 +1107,7 @@ ${this.getAdditionalItemGroups().join(`\n${indent}`)} ); } result.push( - `${this.generation.constants.formatting.indent}${this.generation.constants.formatting.indent}net462;net8.0;net9.0;netstandard2.0` + `${this.generation.constants.formatting.indent}${this.generation.constants.formatting.indent}${TARGET_FRAMEWORKS.join(";")}` ); result.push( `${this.generation.constants.formatting.indent}${this.generation.constants.formatting.indent}enable` @@ -1131,15 +1154,81 @@ ${this.getAdditionalItemGroups().join(`\n${indent}`)} ); } - if (this.githubUrl != null) { - result.push(`${this.githubUrl}`); - } + result.push(...this.getPackageMetadataProperties()); + result.push("true"); return result; } + /** + * NuGet package metadata and XML documentation properties, sourced from the + * `package-metadata` and `generate-documentation-file` config options and + * falling back to values derived from the IR (e.g. the GitHub URL). + */ + private getPackageMetadataProperties(): string[] { + const result: string[] = []; + const metadata = this.generation.settings.packageMetadata; + + if (this.generation.settings.generateDocumentationFile) { + result.push("true"); + // Publishing XML docs should not force every undocumented public + // member to emit CS1591. + result.push("$(NoWarn);CS1591"); + } + + if (metadata.description != null) { + result.push(`${escapeXml(metadata.description)}`); + } + const authors = joinMetadataList(metadata.authors, ","); + if (authors != null) { + result.push(`${escapeXml(authors)}`); + } + const tags = joinMetadataList(metadata.tags, ";"); + if (tags != null) { + result.push(`${escapeXml(tags)}`); + } + if (metadata.copyright != null) { + result.push(`${escapeXml(metadata.copyright)}`); + } + if (metadata.icon != null) { + result.push(`${escapeXml(path.basename(metadata.icon))}`); + } + + const projectUrl = metadata["project-url"] ?? this.githubUrl; + if (projectUrl != null) { + result.push(`${escapeXml(projectUrl)}`); + } + const repositoryUrl = metadata["repository-url"] ?? this.githubUrl; + if (repositoryUrl != null) { + result.push(`${escapeXml(repositoryUrl)}`); + result.push(`${escapeXml(metadata["repository-type"] ?? "git")}`); + } + + if (metadata["include-symbols"]) { + result.push("true"); + result.push("snupkg"); + } + if (metadata["include-source-link"]) { + result.push("true"); + result.push("true"); + result.push("true"); + } + + return result; + } + private getAdditionalItemGroups(): string[] { const result: string[] = []; + const icon = this.generation.settings.packageMetadata.icon; + if (icon != null) { + // The configured path is relative to the root of the generated output, + // matching how a custom license file is referenced below. + result.push(` + + + +`); + } if (this.license != null && this.license.type === "custom") { result.push(` @@ -1195,3 +1284,12 @@ const PLATFORM_HEADERS_INBOX_PACKAGE = { name: "System.Runtime.InteropServices.RuntimeInformation", version: "4.3.0" } as const; + +/** + * Enables SourceLink for GitHub-hosted repositories, so debuggers can step into + * the SDK sources. Only emitted when `package-metadata.include-source-link` is on. + */ +const SOURCE_LINK_PACKAGE = { + name: "Microsoft.SourceLink.GitHub", + version: "8.0.0" +} as const; diff --git a/generators/csharp/base/src/project/__test__/targetFrameworks.test.ts b/generators/csharp/base/src/project/__test__/targetFrameworks.test.ts new file mode 100644 index 000000000000..0f7b0db08106 --- /dev/null +++ b/generators/csharp/base/src/project/__test__/targetFrameworks.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from "vitest"; + +import { getTargetFrameworkRequirements, TARGET_FRAMEWORKS } from "../targetFrameworks.js"; + +describe("getTargetFrameworkRequirements", () => { + it("renders the generated project's target frameworks", () => { + expect(getTargetFrameworkRequirements()).toEqual([ + ".NET 8 and above", + ".NET Framework 4.6.2 and above", + ".NET Standard 2.0 and above" + ]); + }); + + it("collapses modern .NET versions into the lowest one", () => { + expect(getTargetFrameworkRequirements(["net9.0", "net10.0", "net8.0"])).toEqual([".NET 8 and above"]); + }); + + it("renders two-digit .NET Framework monikers", () => { + expect(getTargetFrameworkRequirements(["net48"])).toEqual([".NET Framework 4.8 and above"]); + }); + + it("ignores unrecognized monikers", () => { + expect(getTargetFrameworkRequirements(["net8.0-android", "nonsense"])).toEqual([]); + }); + + it("returns an empty list when there are no target frameworks", () => { + expect(getTargetFrameworkRequirements([])).toEqual([]); + }); + + it("keeps the csproj and requirements in sync", () => { + expect(TARGET_FRAMEWORKS.join(";")).toBe("net462;net8.0;net9.0;netstandard2.0"); + }); +}); diff --git a/generators/csharp/base/src/project/index.ts b/generators/csharp/base/src/project/index.ts index 30acd4190743..94d58ea05ba4 100644 --- a/generators/csharp/base/src/project/index.ts +++ b/generators/csharp/base/src/project/index.ts @@ -1,3 +1,4 @@ export { CSharpFile } from "./CSharpFile.js"; export { CsharpProject } from "./CsharpProject.js"; export * from "./PackageUtilities.js"; +export { getTargetFrameworkRequirements, TARGET_FRAMEWORKS } from "./targetFrameworks.js"; diff --git a/generators/csharp/base/src/project/targetFrameworks.ts b/generators/csharp/base/src/project/targetFrameworks.ts new file mode 100644 index 000000000000..ed9104762025 --- /dev/null +++ b/generators/csharp/base/src/project/targetFrameworks.ts @@ -0,0 +1,50 @@ +/** + * The target frameworks every generated SDK project builds against. + */ +export const TARGET_FRAMEWORKS = ["net462", "net8.0", "net9.0", "netstandard2.0"] as const; + +const NET_FRAMEWORK_PATTERN = /^net(\d)(\d)(\d)?$/; +const NET_STANDARD_PATTERN = /^netstandard(\d+)\.(\d+)$/; +const NET_CORE_PATTERN = /^net(\d+)\.(\d+)$/; + +/** + * Renders the target frameworks as human-readable prerequisites for the README's + * requirements section, e.g. `net8.0` -> ".NET 8 and above". + * + * Consecutive modern .NET versions collapse into their lowest entry, since + * ".NET 8 and above" already covers `net9.0`. + */ +export function getTargetFrameworkRequirements(targetFrameworks: readonly string[] = TARGET_FRAMEWORKS): string[] { + const requirements: string[] = []; + let lowestNetCoreMajor: number | undefined; + + for (const targetFramework of targetFrameworks) { + const netCore = NET_CORE_PATTERN.exec(targetFramework); + if (netCore?.[1] != null) { + const major = Number.parseInt(netCore[1], 10); + if (lowestNetCoreMajor == null || major < lowestNetCoreMajor) { + lowestNetCoreMajor = major; + } + continue; + } + + const netStandard = NET_STANDARD_PATTERN.exec(targetFramework); + if (netStandard?.[1] != null && netStandard[2] != null) { + requirements.push(`.NET Standard ${netStandard[1]}.${netStandard[2]} and above`); + continue; + } + + const netFramework = NET_FRAMEWORK_PATTERN.exec(targetFramework); + if (netFramework?.[1] != null && netFramework[2] != null) { + const version = [netFramework[1], netFramework[2], netFramework[3]] + .filter((part) => part != null) + .join("."); + requirements.push(`.NET Framework ${version} and above`); + } + } + + if (lowestNetCoreMajor != null) { + requirements.unshift(`.NET ${lowestNetCoreMajor} and above`); + } + return requirements; +} diff --git a/generators/csharp/codegen/src/__test__/XmlDocWriter.test.ts b/generators/csharp/codegen/src/__test__/XmlDocWriter.test.ts index 98489b6d4e30..cbea5d184a49 100644 --- a/generators/csharp/codegen/src/__test__/XmlDocWriter.test.ts +++ b/generators/csharp/codegen/src/__test__/XmlDocWriter.test.ts @@ -42,6 +42,49 @@ function escapeXmlDocContent(text: string): string { return writer.toString(); } +describe("XmlDocWriter.toCrefTarget", () => { + it("should keep a simple type name", () => { + expect(XmlDocWriter.toCrefTarget("string")).toBe("string"); + expect(XmlDocWriter.toCrefTarget("MyClass")).toBe("MyClass"); + }); + + it("should keep a namespace-qualified type name", () => { + expect(XmlDocWriter.toCrefTarget("System.Text.Json.Nodes.JsonNode")).toBe("System.Text.Json.Nodes.JsonNode"); + }); + + it("should drop nullable annotations", () => { + expect(XmlDocWriter.toCrefTarget("object?")).toBe("object"); + expect(XmlDocWriter.toCrefTarget("MyClass?")).toBe("MyClass"); + }); + + it("should convert generics to brace syntax with framework type names", () => { + expect(XmlDocWriter.toCrefTarget("List")).toBe("List{String}"); + expect(XmlDocWriter.toCrefTarget("IEnumerable")).toBe("IEnumerable{Int32}"); + expect(XmlDocWriter.toCrefTarget("Dictionary")).toBe("Dictionary{String, Object}"); + }); + + it("should keep non-keyword generic arguments as written", () => { + expect(XmlDocWriter.toCrefTarget("IEnumerable")).toBe("IEnumerable{MyClass}"); + expect(XmlDocWriter.toCrefTarget("OneOf?")).toBe("OneOf{Foo, Bar}"); + }); + + it("should reject nested generic arguments, which cannot be cref identifiers", () => { + expect(XmlDocWriter.toCrefTarget("IEnumerable>")).toBeUndefined(); + expect(XmlDocWriter.toCrefTarget("Dictionary>")).toBeUndefined(); + }); + + it("should reject arrays, which cannot be cref identifiers", () => { + expect(XmlDocWriter.toCrefTarget("byte[]")).toBeUndefined(); + expect(XmlDocWriter.toCrefTarget("IEnumerable")).toBeUndefined(); + }); + + it("should reject types that are not plain names", () => { + expect(XmlDocWriter.toCrefTarget("")).toBeUndefined(); + expect(XmlDocWriter.toCrefTarget("(string, int)")).toBeUndefined(); + expect(XmlDocWriter.toCrefTarget("global::MyNamespace.MyClass")).toBeUndefined(); + }); +}); + describe("XmlDocWriter.escapeXmlDocContent", () => { describe("converts HTML tags to XMLDoc equivalents", () => { it("should convert inline to ", () => { @@ -213,6 +256,50 @@ describe("XmlDocWriter.escapeXmlDocContent", () => { }); }); + describe("escapes bare ampersands", () => { + it("should escape a standalone ampersand", () => { + const result = escapeXmlDocContent("- &: HTML entities"); + expect(result).toBe("- &: HTML entities"); + }); + + it("should escape ampersands in urls", () => { + const result = escapeXmlDocContent("/search?a=1&b=2"); + expect(result).toBe("/search?a=1&b=2"); + }); + + it("should not double-escape existing entities", () => { + const result = escapeXmlDocContent("& < >"); + expect(result).toBe("& < >"); + }); + + it("should escape ampersands alongside angle brackets", () => { + const result = escapeXmlDocContent("List & Dictionary"); + expect(result).toBe("List<string> & Dictionary<string, int>"); + }); + }); + + describe("escapes attribute values", () => { + it("should escape ampersands in a converted link href", () => { + const result = escapeXmlDocContent('See here'); + expect(result).toBe('See here'); + }); + + it("should not double-escape entities already in a href", () => { + const result = escapeXmlDocContent('See here'); + expect(result).toBe('See here'); + }); + + it("should escape ampersands in preserved tag attributes", () => { + const result = escapeXmlDocContent('See here'); + expect(result).toBe('See here'); + }); + + it("should escape angle brackets and quotes in attribute values", () => { + const result = escapeXmlDocContent(''); + expect(result).toBe(''); + }); + }); + describe("handles mixed content", () => { it("should handle comparison within sentence with converted link", () => { const result = escapeXmlDocContent('When x < y, see docs'); diff --git a/generators/csharp/codegen/src/ast/core/Writer.ts b/generators/csharp/codegen/src/ast/core/Writer.ts index 409eb3984ca3..ab85868293e2 100644 --- a/generators/csharp/codegen/src/ast/core/Writer.ts +++ b/generators/csharp/codegen/src/ast/core/Writer.ts @@ -1,4 +1,4 @@ -import { AbstractWriter } from "@fern-api/browser-compatible-base-generator"; +import { AbstractAstNode, AbstractWriter } from "@fern-api/browser-compatible-base-generator"; import { Generation } from "../../context/generation-info.js"; import { type ClassReference } from "../types/ClassReference.js"; @@ -85,6 +85,31 @@ export class Writer extends AbstractWriter { this.typeScopeStack.pop(); } + /* Renders the node in isolation and returns the result instead of appending it to this + writer's buffer. References collected while rendering are forwarded to this writer so + that the imports the node depends on are still emitted. */ + public renderNodeToString(node: AbstractAstNode): string { + const scratch = new Writer({ + namespace: this.namespace, + allNamespaceSegments: this.allNamespaceSegments, + allTypeClassReferences: this.allTypeClassReferences, + generation: this.generation, + skipImports: this.skipImports, + skipGlobalQualifier: this.skipGlobalQualifier + }); + for (const enclosingType of this.typeScopeStack) { + scratch.pushTypeScope(enclosingType); + } + scratch.writeNode(node); + for (const [namespace, references] of Object.entries(scratch.references)) { + this.addNamespace(namespace); + for (const reference of references) { + this.addReference(reference); + } + } + return scratch.toString(true); + } + public addNamespace(namespace: string): void { const foundNamespace = this.references[namespace]; if (foundNamespace == null) { diff --git a/generators/csharp/codegen/src/ast/core/XmlDocWriter.ts b/generators/csharp/codegen/src/ast/core/XmlDocWriter.ts index ce6f0b71adaa..637da6a67e91 100644 --- a/generators/csharp/codegen/src/ast/core/XmlDocWriter.ts +++ b/generators/csharp/codegen/src/ast/core/XmlDocWriter.ts @@ -73,6 +73,33 @@ export class XmlDocWriter { "tbody" ]); + // Matches an ampersand that does not already begin a character or entity reference + private static readonly BARE_AMPERSAND_PATTERN = /&(?!(?:[a-zA-Z][a-zA-Z0-9]*|#[0-9]+|#x[0-9a-fA-F]+);)/g; + + // A (possibly namespace-qualified) type name, optionally followed by generic arguments + private static readonly TYPE_NAME_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)(?:<(.+)>)?$/; + private static readonly IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_.]*$/; + + // Generic arguments in a cref must be identifiers, so keyword aliases are replaced by the + // framework type they alias + private static readonly KEYWORD_ALIASES: Record = { + bool: "Boolean", + byte: "Byte", + char: "Char", + decimal: "Decimal", + double: "Double", + float: "Single", + int: "Int32", + long: "Int64", + object: "Object", + sbyte: "SByte", + short: "Int16", + string: "String", + uint: "UInt32", + ulong: "UInt64", + ushort: "UInt16" + }; + private writer: Writer; private wrotePrefixOnCurrentLine: boolean = false; constructor(writer: Writer) { @@ -137,6 +164,76 @@ export class XmlDocWriter { this.writer.writeNode(node); } + /** + * Writes a documentation reference to a type. Types that can be expressed as a + * documentation comment identifier are written as `` so that the + * compiler resolves them and IDEs link them; anything else falls back to inline code. + */ + public writeSeeType(type: AstNode): void { + const rendered = this.writer.renderNodeToString(type); + const crefTarget = XmlDocWriter.toCrefTarget(rendered); + if (crefTarget != null) { + this.write(``); + return; + } + this.write(`${this.escapeXmlDocContent(rendered)}`); + } + + /** + * Converts C# source syntax for a type into a documentation comment identifier, or returns + * undefined when the type cannot be expressed as one. + * + * Nullable annotations are dropped (`object?` -> `object`) because they are not part of a + * type's identifier, and generic arguments use brace syntax (`List` -> `List{Foo}`) + * because crefs are resolved by the compiler rather than rendered as text. Generic arguments + * must be identifiers, so keyword aliases become framework type names + * (`List` -> `List{String}`) and arrays or nested generic arguments are rejected. + */ + public static toCrefTarget(renderedType: string): string | undefined { + const type = renderedType.trim().replaceAll("?", ""); + const match = XmlDocWriter.TYPE_NAME_PATTERN.exec(type); + if (match == null) { + return undefined; + } + const [, name, genericArguments] = match; + if (name == null) { + return undefined; + } + if (genericArguments == null) { + return name; + } + const crefArguments: string[] = []; + for (const argument of XmlDocWriter.splitGenericArguments(genericArguments)) { + const identifier = XmlDocWriter.KEYWORD_ALIASES[argument] ?? argument; + if (!XmlDocWriter.IDENTIFIER_PATTERN.test(identifier)) { + return undefined; + } + crefArguments.push(identifier); + } + return crefArguments.length === 0 ? undefined : `${name}{${crefArguments.join(", ")}}`; + } + + private static splitGenericArguments(genericArguments: string): string[] { + const arguments_: string[] = []; + let depth = 0; + let current = ""; + for (const character of genericArguments) { + if (character === "," && depth === 0) { + arguments_.push(current.trim()); + current = ""; + continue; + } + if (character === "<") { + depth++; + } else if (character === ">") { + depth--; + } + current += character; + } + arguments_.push(current.trim()); + return arguments_; + } + public writeXmlNode(nodeName: string, text: string): void { this.writePrefix(); this.writeOpenXmlNode(nodeName); @@ -198,7 +295,10 @@ export class XmlDocWriter { } return match; }); - const escaped = withPlaceholders.replaceAll("<", "<").replaceAll(">", ">"); + const escaped = withPlaceholders + .replace(XmlDocWriter.BARE_AMPERSAND_PATTERN, "&") + .replaceAll("<", "<") + .replaceAll(">", ">"); return escaped.replace(/\uE000(\d+)\uE000/g, (_, index: string) => tags[parseInt(index, 10)] ?? ""); } @@ -283,7 +383,7 @@ export class XmlDocWriter { case "a": { const href = el.attribs.href; if (href) { - return `${children}`; + return `${children}`; } return children; } @@ -316,7 +416,7 @@ export class XmlDocWriter { // Known XMLDoc tags: pass through with attributes if (XmlDocWriter.SAFE_XML_DOC_TAGS.has(tag)) { const attrs = Object.entries(el.attribs) - .map(([k, v]) => ` ${k}="${v}"`) + .map(([k, v]) => ` ${k}="${XmlDocWriter.escapeXmlAttributeValue(v)}"`) .join(""); if (el.children.length === 0) { return `<${el.name}${attrs}/>`; @@ -329,6 +429,19 @@ export class XmlDocWriter { } } + /** + * Escapes the markup characters that are not allowed raw inside an XML attribute value. + * Ampersands that already begin a character or entity reference are left alone so that + * values such as `?a=1&b=2` are not double escaped. + */ + private static escapeXmlAttributeValue(value: string): string { + return value + .replace(XmlDocWriter.BARE_AMPERSAND_PATTERN, "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """); + } + private decodeHtmlEntities(text: string): string { const entityMap: Record = { "+": "+", diff --git a/generators/csharp/codegen/src/context/generation-info.ts b/generators/csharp/codegen/src/context/generation-info.ts index e1e3eef4dc95..67a7712b051f 100644 --- a/generators/csharp/codegen/src/context/generation-info.ts +++ b/generators/csharp/codegen/src/context/generation-info.ts @@ -209,6 +209,10 @@ export class Generation { rootNamespaceForCoreClasses: () => this.customConfig["root-namespace-for-core-classes"] ?? true, /** Custom NuGet package identifier. Default: "" (uses root namespace). */ packageId: () => this.customConfig["package-id"] ?? "", + /** When true, the generated csproj emits XML documentation so the nupkg ships `.xml`. Default: true. */ + generateDocumentationFile: () => this.customConfig["generate-documentation-file"] ?? true, + /** NuGet package metadata (description, authors, tags, icon, urls, SourceLink, symbols) for the generated csproj. Default: {}. */ + packageMetadata: () => this.customConfig["package-metadata"] ?? {}, /** When true, generates enums that can handle unknown/future values gracefully. Default: true. */ isForwardCompatibleEnumsEnabled: () => this.customConfig["enable-forward-compatible-enums"] ?? diff --git a/generators/csharp/codegen/src/custom-config/CsharpConfigSchema.ts b/generators/csharp/codegen/src/custom-config/CsharpConfigSchema.ts index 592190975370..2c01a21a4f47 100644 --- a/generators/csharp/codegen/src/custom-config/CsharpConfigSchema.ts +++ b/generators/csharp/codegen/src/custom-config/CsharpConfigSchema.ts @@ -27,6 +27,42 @@ export const OutputPathSchema = z.union([ export type OutputPathSchema = z.infer; +/** + * Schema for NuGet package metadata written into the generated csproj. + * + * Every field is optional; unset fields are omitted from the csproj so NuGet + * falls back to its own defaults (or to values already derived from the IR, + * such as the license and the GitHub project URL). + */ +export const PackageMetadataSchema = z.object({ + /** `` — the package description shown on nuget.org. */ + description: z.string().optional(), + /** `` — a single author or a list of authors. */ + authors: z.union([z.string(), z.array(z.string())]).optional(), + /** `` — search tags, either space-separated or a list. */ + tags: z.union([z.string(), z.array(z.string())]).optional(), + /** ``. */ + copyright: z.string().optional(), + /** + * `` — path to an image, relative to the project directory, + * that is packed into the nupkg. The file itself must be present in the + * output (e.g. committed and listed in `.fernignore`). + */ + icon: z.string().optional(), + /** `` — overrides the URL derived from the GitHub output location. */ + "project-url": z.string().optional(), + /** `` — defaults to the GitHub output location when unset. */ + "repository-url": z.string().optional(), + /** ``. Default: "git" when a repository URL is present. */ + "repository-type": z.string().optional(), + /** When true, adds Microsoft.SourceLink.GitHub and enables deterministic, source-linked builds. Default: false. */ + "include-source-link": z.boolean().optional(), + /** When true, produces a `.snupkg` symbol package alongside the `.nupkg`. Default: false. */ + "include-symbols": z.boolean().optional() +}); + +export type PackageMetadataSchema = z.infer; + export const CsharpConfigSchema = z.object({ // Influence dynamic snippets. namespace: z.string().optional(), @@ -98,6 +134,13 @@ export const CsharpConfigSchema = z.object({ "enable-forward-compatible-enums": z.boolean().optional(), "generate-error-types": z.boolean().optional(), "package-id": z.string().optional(), + // When true, the generated csproj sets , so the + // published nupkg ships `lib//.xml` and consumers get + // IntelliSense. CS1591 (missing XML comment for a public member) is + // suppressed so enabling docs does not add warnings for undocumented types. + "generate-documentation-file": z.boolean().optional(), + // NuGet package metadata written into the generated csproj. + "package-metadata": PackageMetadataSchema.optional(), "generate-mock-server-tests": z.boolean().optional(), "enable-wire-tests": z.boolean().optional(), "include-exception-handler": z.boolean().optional(), diff --git a/generators/csharp/model/src/undiscriminated-union/UndiscriminatedUnionGenerator.ts b/generators/csharp/model/src/undiscriminated-union/UndiscriminatedUnionGenerator.ts index 800a74ea479a..8580fb288b87 100644 --- a/generators/csharp/model/src/undiscriminated-union/UndiscriminatedUnionGenerator.ts +++ b/generators/csharp/model/src/undiscriminated-union/UndiscriminatedUnionGenerator.ts @@ -219,8 +219,8 @@ export class UndiscriminatedUnionGenerator extends FileGenerator { - writer.write(`Factory method to create a union from a `); - writer.writeNode(member.csharpType); + writer.write("Factory method to create a union from a "); + writer.writeSeeType(member.csharpType); writer.write(" value."); } }, @@ -293,10 +293,10 @@ export class UndiscriminatedUnionGenerator extends FileGenerator { - writer.write(`Returns the value as a if is '${escapeForCSharpString(member.discriminator)}', otherwise throws an exception.` + ` if is '${escapeForCSharpString(member.discriminator)}', otherwise throws an exception.` ); }, exceptions: new Map([ @@ -364,9 +364,9 @@ export class UndiscriminatedUnionGenerator extends FileGenerator { - writer.write(`Attempts to cast the value to a and returns true if successful.`); + writer.write("Attempts to cast the value to a "); + writer.writeSeeType(member.csharpType); + writer.write(" and returns true if successful."); } }, access: ast.Access.Public, diff --git a/generators/csharp/model/src/union/UnionGenerator.ts b/generators/csharp/model/src/union/UnionGenerator.ts index fd8bb2d59fff..2ba68e9292d0 100644 --- a/generators/csharp/model/src/union/UnionGenerator.ts +++ b/generators/csharp/model/src/union/UnionGenerator.ts @@ -155,9 +155,9 @@ export class UnionGenerator extends FileGenerator { - writer.write(`Create an instance of ${this.classReference.name} with .'); + writer.write(`Create an instance of ${this.classReference.name} with `); + writer.writeSeeType(innerClassType); + writer.write("."); } }, access: ast.Access.Public, @@ -200,10 +200,10 @@ export class UnionGenerator extends FileGenerator { - writer.write('Returns the value as a if is '${escapeForCSharpString(getWireValue(type.discriminantValue))}', otherwise throws an exception.` + ` if is '${escapeForCSharpString(getWireValue(type.discriminantValue))}', otherwise throws an exception.` ); }, exceptions: new Map([ @@ -334,9 +334,9 @@ export class UnionGenerator extends FileGenerator { - writer.write('Attempts to cast the value to a and returns true if successful.'); + writer.write("Attempts to cast the value to a "); + writer.writeSeeType(memberType); + writer.write(" and returns true if successful."); } }, access: ast.Access.Public, diff --git a/generators/csharp/sdk/changes/unreleased/feat-docs-and-package-metadata.yml b/generators/csharp/sdk/changes/unreleased/feat-docs-and-package-metadata.yml new file mode 100644 index 000000000000..d76746579f92 --- /dev/null +++ b/generators/csharp/sdk/changes/unreleased/feat-docs-and-package-metadata.yml @@ -0,0 +1,17 @@ +# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json + +- summary: | + Added a `generate-documentation-file` config option (default `true`) so the + generated csproj emits XML documentation and the published NuGet package ships + `lib//.xml`, giving consumers IntelliSense. CS1591 is + suppressed so enabling documentation does not introduce warnings for + undocumented members. + type: feat + +- summary: | + Added a `package-metadata` config block for NuGet metadata written into the + generated csproj: `description`, `authors`, `tags`, `copyright`, `icon`, + `project-url`, `repository-url`, `repository-type`, `include-source-link` + (adds `Microsoft.SourceLink.GitHub`) and `include-symbols` (produces a + `.snupkg`). + type: feat diff --git a/generators/csharp/sdk/changes/unreleased/fix-client-options-global-headers.yml b/generators/csharp/sdk/changes/unreleased/fix-client-options-global-headers.yml new file mode 100644 index 000000000000..be2c2ad867b8 --- /dev/null +++ b/generators/csharp/sdk/changes/unreleased/fix-client-options-global-headers.yml @@ -0,0 +1,16 @@ +# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json + +- summary: | + Global header values set on `ClientOptions` are now respected in the default + (non-unified) client shape. Previously the generated root client read only the + constructor parameter for a promoted global header, so + `new Client(clientOptions: new ClientOptions { Version = "..." })` was silently + ignored and a stray environment variable could win instead. The resolution + order is now: explicit constructor argument, `ClientOptions` property, + environment variable, then the literal/client default. + type: fix + +- summary: | + `ClientOptions.Clone()` now copies literal global header properties (e.g. + `Version`), which were previously dropped when the options were cloned. + type: fix diff --git a/generators/csharp/sdk/changes/unreleased/fix-doc-comment-attribute-escaping.yml b/generators/csharp/sdk/changes/unreleased/fix-doc-comment-attribute-escaping.yml new file mode 100644 index 000000000000..40359f6ae66a --- /dev/null +++ b/generators/csharp/sdk/changes/unreleased/fix-doc-comment-attribute-escaping.yml @@ -0,0 +1,6 @@ +- summary: | + Escape markup characters in the attribute values of documentation comment tags. Descriptions + containing links such as `` no longer emit invalid + XML (CS1570) in generated documentation comments, while attribute values that already contain + character or entity references are left untouched. + type: fix diff --git a/generators/csharp/sdk/changes/unreleased/fix-readme-requirements.yml b/generators/csharp/sdk/changes/unreleased/fix-readme-requirements.yml new file mode 100644 index 000000000000..2b302891df6d --- /dev/null +++ b/generators/csharp/sdk/changes/unreleased/fix-readme-requirements.yml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json + +- summary: | + The generated README's `## Requirements` section is now populated with the + project's target frameworks (".NET 8 and above", ".NET Framework 4.6.2 and + above", ".NET Standard 2.0 and above"). Previously the C# generator passed an + empty requirements list, so the section rendered as a dangling + "This SDK requires:" with no entries. + type: fix diff --git a/generators/csharp/sdk/changes/unreleased/fix-readme-snippets.yml b/generators/csharp/sdk/changes/unreleased/fix-readme-snippets.yml new file mode 100644 index 000000000000..6d510f5dbdf3 --- /dev/null +++ b/generators/csharp/sdk/changes/unreleased/fix-readme-snippets.yml @@ -0,0 +1,14 @@ +# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json + +- summary: | + README and dynamic snippets no longer pass an upper-cased placeholder for + global header constructor parameters (e.g. `new Client("TOKEN", "VERSION")`, + which sent the literal header value `VERSION` at runtime). Snippets now use + the header's literal or client default value when one is known. + type: fix + +- summary: | + Fixed invalid C# in the generated README: `RequestOptions` examples used + object-initializer syntax with `:` instead of `=` (`new RequestOptions { MaxRetries: 0 }`), + and the `WithRawResponse` section declared `var data` twice in one block. + type: fix diff --git a/generators/csharp/sdk/changes/unreleased/fix-union-cref-doc-comments.yml b/generators/csharp/sdk/changes/unreleased/fix-union-cref-doc-comments.yml new file mode 100644 index 000000000000..f6dd9c67b5fb --- /dev/null +++ b/generators/csharp/sdk/changes/unreleased/fix-union-cref-doc-comments.yml @@ -0,0 +1,8 @@ +- summary: | + Fix invalid `` documentation comments generated for union types. Type names + are now converted to documentation comment identifiers (`List` becomes + `List{String}`, `object?` becomes `object`), and types that cannot be expressed as an + identifier (arrays, nested generic arguments) are rendered as escaped inline code instead. + This removes CS1570/CS1584/CS1658 warnings from generated SDKs that contain unions when XML + documentation is enabled. + type: fix diff --git a/generators/csharp/sdk/changes/unreleased/fix-xml-doc-comments.yml b/generators/csharp/sdk/changes/unreleased/fix-xml-doc-comments.yml new file mode 100644 index 000000000000..5bb1a921fd53 --- /dev/null +++ b/generators/csharp/sdk/changes/unreleased/fix-xml-doc-comments.yml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json + +- summary: | + Escaped generic type syntax in the XML doc comments of the generated core + files (`Optional`, `OptionalAttribute`, `NullableAttribute`, `Extensions`), + and added the missing `param` tags on `Extensions.Assert`. Building generated + SDKs with XML documentation enabled no longer emits CS1570/CS1573 warnings. + type: fix diff --git a/generators/csharp/sdk/src/options/BaseOptionsGenerator.ts b/generators/csharp/sdk/src/options/BaseOptionsGenerator.ts index 30ffefdf9cdd..4891ddfc3524 100644 --- a/generators/csharp/sdk/src/options/BaseOptionsGenerator.ts +++ b/generators/csharp/sdk/src/options/BaseOptionsGenerator.ts @@ -179,11 +179,11 @@ export class BaseOptionsGenerator extends WithGeneration { header: HttpHeader; options: OptionArgs; } - ) { + ): ast.Field | undefined { if (header.valueType.type !== "container" || header.valueType.container.type !== "literal") { - return; + return undefined; } - classOrInterface.addField({ + return classOrInterface.addField({ access: ast.Access.Public, origin: header, get: true, @@ -251,13 +251,19 @@ export class BaseOptionsGenerator extends WithGeneration { this.getBodyPropertiesField(iface, optionArgs); } - public getLiteralHeaderOptions(classOrInterface: ast.Interface | ast.Class, optionArgs: OptionArgs) { + /** Adds a client option for every literal-typed global header, and returns the added fields. */ + public getLiteralHeaderOptions(classOrInterface: ast.Interface | ast.Class, optionArgs: OptionArgs): ast.Field[] { + const fields: ast.Field[] = []; for (const header of this.context.ir.headers) { - this.maybeGetLiteralHeaderField(classOrInterface, { + const field = this.maybeGetLiteralHeaderField(classOrInterface, { header, options: optionArgs }); + if (field != null) { + fields.push(field); + } } + return fields; } private getLiteralRootClientParameterType({ literal }: { literal: Literal }): ast.Type { diff --git a/generators/csharp/sdk/src/options/ClientOptionsGenerator.ts b/generators/csharp/sdk/src/options/ClientOptionsGenerator.ts index b46f2f704896..2990fc434f0b 100644 --- a/generators/csharp/sdk/src/options/ClientOptionsGenerator.ts +++ b/generators/csharp/sdk/src/options/ClientOptionsGenerator.ts @@ -35,6 +35,8 @@ export class ClientOptionsGenerator extends FileGenerator `\n ${field.name} = ${field.name},`) .join(""); + const literalHeaderFieldLines = this.literalHeaderFields + .map((field) => `\n ${field.name} = ${field.name},`) + .join(""); writer.writeStatement( `return new ClientOptions {${this.baseUrlField ? `\n ${this.baseUrlField.name} = ${this.baseUrlField.name},` : ""}${this.environmentField ? `\n ${this.environmentField.name} = ${this.environmentField.name},` : ""}${serverVariableFieldLines} @@ -634,7 +639,7 @@ export class ClientOptionsGenerator extends FileGenerator(Headers)), - AdditionalHeaders = AdditionalHeaders,${unifiedFieldLines}${this.appInfoField ? `\n ${this.appInfoField.name} = ${this.appInfoField.name},` : ""} + AdditionalHeaders = AdditionalHeaders,${literalHeaderFieldLines}${unifiedFieldLines}${this.appInfoField ? `\n ${this.appInfoField.name} = ${this.appInfoField.name},` : ""} ${this.settings.includeExceptionHandler ? "ExceptionHandler = ExceptionHandler.Clone()," : ""} }` ); @@ -705,6 +710,9 @@ export class ClientOptionsGenerator extends FileGenerator(other.Headers))" ); writer.writeLine("AdditionalHeaders = other.AdditionalHeaders;"); + for (const field of this.literalHeaderFields) { + writer.writeLine(`${field.name} = other.${field.name};`); + } for (const field of this.unifiedFields) { writer.writeLine(`${field.name} = other.${field.name};`); } diff --git a/generators/csharp/sdk/src/readme/ReadmeConfigBuilder.ts b/generators/csharp/sdk/src/readme/ReadmeConfigBuilder.ts index efbd2d2481fd..80d5685b5f87 100644 --- a/generators/csharp/sdk/src/readme/ReadmeConfigBuilder.ts +++ b/generators/csharp/sdk/src/readme/ReadmeConfigBuilder.ts @@ -1,3 +1,4 @@ +import { getTargetFrameworkRequirements } from "@fern-api/csharp-base"; import { CsharpConfigSchema } from "@fern-api/csharp-codegen"; import { Logger } from "@fern-api/logger"; import { FernGeneratorCli } from "@fern-fern/generator-cli-sdk"; @@ -46,7 +47,7 @@ export class ReadmeConfigBuilder { referenceMarkdownPath: "./reference.md", customSections: getCustomSections(context), features, - requirements: [] + requirements: getTargetFrameworkRequirements() }; } diff --git a/generators/csharp/sdk/src/readme/ReadmeSnippetBuilder.ts b/generators/csharp/sdk/src/readme/ReadmeSnippetBuilder.ts index 24f3825e8560..2d0e3e77941f 100644 --- a/generators/csharp/sdk/src/readme/ReadmeSnippetBuilder.ts +++ b/generators/csharp/sdk/src/readme/ReadmeSnippetBuilder.ts @@ -157,7 +157,7 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder { var response = await ${this.getMethodCall(retryEndpoint)}( ..., new ${this.requestOptionsName} { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); `) @@ -171,7 +171,7 @@ var response = await ${this.getMethodCall(retryEndpoint)}( var response = await ${this.getMethodCall(timeoutEndpoint)}( ..., new ${this.requestOptionsName} { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); `) @@ -231,7 +231,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await ${this.getMethodCall(rawResponseEndpoint)}(...); +var parsedData = await ${this.getMethodCall(rawResponseEndpoint)}(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/generators/csharp/sdk/src/root-client/RootClientGenerator.ts b/generators/csharp/sdk/src/root-client/RootClientGenerator.ts index 787cfa6f3424..32a5695b5962 100644 --- a/generators/csharp/sdk/src/root-client/RootClientGenerator.ts +++ b/generators/csharp/sdk/src/root-client/RootClientGenerator.ts @@ -65,6 +65,12 @@ interface ConstructorParameter { * Falls back to parameter name if not provided */ exampleValue?: string; + /** + * A rendered C# expression to use in examples, for parameters whose value is known at + * compile time (a `literal<"...">`-typed or `client-default`ed global header). Takes + * precedence over `exampleValue`, which is quoted as a string. + */ + exampleExpression?: string; /** * The client default value from x-fern-default. * When present, the parameter is optional and uses this value as fallback. @@ -94,6 +100,18 @@ function getLiteralHeaderValue(param: ConstructorParameter): Literal | undefined : undefined; } +/** Renders a literal as the C# expression for its value. */ +function renderLiteral(literal: Literal): string { + switch (literal.type) { + case "string": + return `"${escapeForCSharpString(literal.string)}"`; + case "boolean": + return literal.boolean ? "true" : "false"; + default: + assertNever(literal); + } +} + export class RootClientGenerator extends FileGenerator { private rawClient: RawClient; private serviceId: ServiceId | undefined; @@ -551,6 +569,14 @@ export class RootClientGenerator extends FileGeneratorsee here for details" + }, + "escapedDocumentationLink": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "See see here for details" } }, "required": [ diff --git a/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/csharp-xml-entities.json b/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/csharp-xml-entities.json index 9d4c6f844bc3..fc2602a3fbed 100644 --- a/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/csharp-xml-entities.json +++ b/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/csharp-xml-entities.json @@ -152,6 +152,72 @@ }, "propertyAccess": null, "variable": null + }, + { + "name": { + "wireValue": "documentationLink", + "name": { + "originalName": "documentationLink", + "camelCase": { + "unsafeName": "documentationLink", + "safeName": "documentationLink" + }, + "snakeCase": { + "unsafeName": "documentation_link", + "safeName": "documentation_link" + }, + "screamingSnakeCase": { + "unsafeName": "DOCUMENTATION_LINK", + "safeName": "DOCUMENTATION_LINK" + }, + "pascalCase": { + "unsafeName": "DocumentationLink", + "safeName": "DocumentationLink" + } + } + }, + "typeReference": { + "type": "optional", + "value": { + "type": "primitive", + "value": "STRING" + } + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "escapedDocumentationLink", + "name": { + "originalName": "escapedDocumentationLink", + "camelCase": { + "unsafeName": "escapedDocumentationLink", + "safeName": "escapedDocumentationLink" + }, + "snakeCase": { + "unsafeName": "escaped_documentation_link", + "safeName": "escaped_documentation_link" + }, + "screamingSnakeCase": { + "unsafeName": "ESCAPED_DOCUMENTATION_LINK", + "safeName": "ESCAPED_DOCUMENTATION_LINK" + }, + "pascalCase": { + "unsafeName": "EscapedDocumentationLink", + "safeName": "EscapedDocumentationLink" + } + } + }, + "typeReference": { + "type": "optional", + "value": { + "type": "primitive", + "value": "STRING" + } + }, + "propertyAccess": null, + "variable": null } ], "extends": null, diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/csharp-xml-entities.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/csharp-xml-entities.json index c5fc67ca619d..be09340c8d40 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/csharp-xml-entities.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/csharp-xml-entities.json @@ -123,6 +123,62 @@ }, "availability": null, "docs": "Special characters:   … · ©" + }, + { + "name": "documentationLink", + "valueType": { + "_type": "container", + "container": { + "_type": "optional", + "optional": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + } + } + }, + "propertyAccess": null, + "defaultValue": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": "See see here for details" + }, + { + "name": "escapedDocumentationLink", + "valueType": { + "_type": "container", + "container": { + "_type": "optional", + "optional": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + } + } + }, + "propertyAccess": null, + "defaultValue": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": "See see here for details" } ], "extra-properties": false, @@ -227,7 +283,7 @@ "autogeneratedExamples": [ { "example": { - "id": "9edac0cd", + "id": "da856427", "url": "/timezone", "name": null, "endpointHeaders": [], @@ -370,6 +426,98 @@ "jsonExample": "specialChars" }, "propertyAccess": null + }, + { + "name": "documentationLink", + "originalTypeDeclaration": { + "name": "TimeZoneModel", + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "displayName": null, + "typeId": "type_:TimeZoneModel" + }, + "value": { + "shape": { + "type": "container", + "container": { + "type": "optional", + "optional": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "documentationLink" + } + } + }, + "jsonExample": "documentationLink" + }, + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + } + } + }, + "jsonExample": "documentationLink" + }, + "propertyAccess": null + }, + { + "name": "escapedDocumentationLink", + "originalTypeDeclaration": { + "name": "TimeZoneModel", + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "displayName": null, + "typeId": "type_:TimeZoneModel" + }, + "value": { + "shape": { + "type": "container", + "container": { + "type": "optional", + "optional": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "escapedDocumentationLink" + } + } + }, + "jsonExample": "escapedDocumentationLink" + }, + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + } + } + }, + "jsonExample": "escapedDocumentationLink" + }, + "propertyAccess": null } ], "extraProperties": null @@ -389,7 +537,9 @@ "timeZoneOffset": "timeZoneOffset", "mathExpression": "mathExpression", "validEntity": "validEntity", - "specialChars": "specialChars" + "specialChars": "specialChars", + "documentationLink": "documentationLink", + "escapedDocumentationLink": "escapedDocumentationLink" } } } @@ -592,6 +742,72 @@ }, "propertyAccess": null, "variable": null + }, + { + "name": { + "wireValue": "documentationLink", + "name": { + "originalName": "documentationLink", + "camelCase": { + "unsafeName": "documentationLink", + "safeName": "documentationLink" + }, + "snakeCase": { + "unsafeName": "documentation_link", + "safeName": "documentation_link" + }, + "screamingSnakeCase": { + "unsafeName": "DOCUMENTATION_LINK", + "safeName": "DOCUMENTATION_LINK" + }, + "pascalCase": { + "unsafeName": "DocumentationLink", + "safeName": "DocumentationLink" + } + } + }, + "typeReference": { + "type": "optional", + "value": { + "type": "primitive", + "value": "STRING" + } + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "escapedDocumentationLink", + "name": { + "originalName": "escapedDocumentationLink", + "camelCase": { + "unsafeName": "escapedDocumentationLink", + "safeName": "escapedDocumentationLink" + }, + "snakeCase": { + "unsafeName": "escaped_documentation_link", + "safeName": "escaped_documentation_link" + }, + "screamingSnakeCase": { + "unsafeName": "ESCAPED_DOCUMENTATION_LINK", + "safeName": "ESCAPED_DOCUMENTATION_LINK" + }, + "pascalCase": { + "unsafeName": "EscapedDocumentationLink", + "safeName": "EscapedDocumentationLink" + } + } + }, + "typeReference": { + "type": "optional", + "value": { + "type": "primitive", + "value": "STRING" + } + }, + "propertyAccess": null, + "variable": null } ], "extends": null, diff --git a/packages/generator-cli/changes/unreleased/fix-empty-readme-requirements.yml b/packages/generator-cli/changes/unreleased/fix-empty-readme-requirements.yml new file mode 100644 index 000000000000..7f1f8dadb044 --- /dev/null +++ b/packages/generator-cli/changes/unreleased/fix-empty-readme-requirements.yml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=../../../../fern-changes-yml.schema.json + +- summary: | + The README's `## Requirements` section is now omitted when the generator + supplies an empty requirements list, instead of rendering a heading followed by + a dangling "This SDK requires:" line. + type: fix diff --git a/packages/generator-cli/src/readme/ReadmeGenerator.ts b/packages/generator-cli/src/readme/ReadmeGenerator.ts index 017ad556896a..66fe14dcbc9f 100644 --- a/packages/generator-cli/src/readme/ReadmeGenerator.ts +++ b/packages/generator-cli/src/readme/ReadmeGenerator.ts @@ -76,7 +76,7 @@ export class ReadmeGenerator { }) ); } - if (this.readmeConfig.requirements != null) { + if (this.readmeConfig.requirements != null && this.readmeConfig.requirements.length > 0) { blocks.push( await this.generateRequirements({ requirements: this.readmeConfig.requirements diff --git a/seed/csharp-sdk/accept-header/README.md b/seed/csharp-sdk/accept-header/README.md index f17383503dbd..32c0b746979c 100644 --- a/seed/csharp-sdk/accept-header/README.md +++ b/seed/csharp-sdk/accept-header/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.EndpointAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.EndpointAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.EndpointAsync(...); +var parsedData = await client.Service.EndpointAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/accept-header/src/SeedAccept.Test/Utils/OptionalComparer.cs index 3c7977535966..6966d7c112f0 100644 --- a/seed/csharp-sdk/accept-header/src/SeedAccept.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/accept-header/src/SeedAccept.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Extensions.cs b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Extensions.cs index 5fc79d21493f..620b5d67a33f 100644 --- a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Extensions.cs +++ b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/NullableAttribute.cs b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/NullableAttribute.cs index 28b5ca870266..0088859e9b13 100644 --- a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedAccept.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedAccept.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Optional.cs b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Optional.cs index c184c18ebc7f..6383bf8dd9ef 100644 --- a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Optional.cs +++ b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/OptionalAttribute.cs b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/OptionalAttribute.cs index feb17b29e6c3..c683ad5b7771 100644 --- a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedAccept.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/QueryStringBuilder.cs b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/QueryStringBuilder.cs index 448ff97a0744..fafefead0ab4 100644 --- a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept/SeedAccept.csproj b/seed/csharp-sdk/accept-header/src/SeedAccept/SeedAccept.csproj index 864f3598097e..dd1f4f13a6f1 100644 --- a/seed/csharp-sdk/accept-header/src/SeedAccept/SeedAccept.csproj +++ b/seed/csharp-sdk/accept-header/src/SeedAccept/SeedAccept.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/accept-header/fern + https://github.com/accept-header/fern + git true diff --git a/seed/csharp-sdk/alias-extends/README.md b/seed/csharp-sdk/alias-extends/README.md index b0125b789b36..fb34ea5dd4f5 100644 --- a/seed/csharp-sdk/alias-extends/README.md +++ b/seed/csharp-sdk/alias-extends/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.ExtendedInlineRequestBodyAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.ExtendedInlineRequestBodyAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.ExtendedInlineRequestBodyAsync(...); +var parsedData = await client.ExtendedInlineRequestBodyAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends.Test/Utils/OptionalComparer.cs index 66b696dcdbcc..a7e576ca72dd 100644 --- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Extensions.cs b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Extensions.cs index ce1b1a20a3dd..0c71f90ef0f7 100644 --- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Extensions.cs +++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/NullableAttribute.cs b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/NullableAttribute.cs index ad21e33cbf3e..4b5450e179ca 100644 --- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedAliasExtends.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedAliasExtends.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Optional.cs b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Optional.cs index 06dbd0e43ece..0b9758148361 100644 --- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Optional.cs +++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/OptionalAttribute.cs b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/OptionalAttribute.cs index 2632a45034ab..1ded89db50ec 100644 --- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedAliasExtends.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/QueryStringBuilder.cs b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/QueryStringBuilder.cs index c3d6fc86da3b..fc8e1861f6ac 100644 --- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/SeedAliasExtends.csproj b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/SeedAliasExtends.csproj index dd5c3d4aee50..d0552c17e36e 100644 --- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/SeedAliasExtends.csproj +++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/SeedAliasExtends.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/alias-extends/fern + https://github.com/alias-extends/fern + git true diff --git a/seed/csharp-sdk/alias/README.md b/seed/csharp-sdk/alias/README.md index 104243ec3ac9..e6ed1038d666 100644 --- a/seed/csharp-sdk/alias/README.md +++ b/seed/csharp-sdk/alias/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetAsync(...); +var parsedData = await client.GetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/alias/src/SeedAlias.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/alias/src/SeedAlias.Test/Utils/OptionalComparer.cs index e91db1abe5f6..b9afc85edb3d 100644 --- a/seed/csharp-sdk/alias/src/SeedAlias.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/alias/src/SeedAlias.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/alias/src/SeedAlias/Core/Extensions.cs b/seed/csharp-sdk/alias/src/SeedAlias/Core/Extensions.cs index 2ff74866d9f5..8a768aa2b936 100644 --- a/seed/csharp-sdk/alias/src/SeedAlias/Core/Extensions.cs +++ b/seed/csharp-sdk/alias/src/SeedAlias/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/alias/src/SeedAlias/Core/NullableAttribute.cs b/seed/csharp-sdk/alias/src/SeedAlias/Core/NullableAttribute.cs index 9ecd5ff22fea..9a845b375cfb 100644 --- a/seed/csharp-sdk/alias/src/SeedAlias/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/alias/src/SeedAlias/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedAlias.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedAlias.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/alias/src/SeedAlias/Core/Optional.cs b/seed/csharp-sdk/alias/src/SeedAlias/Core/Optional.cs index d4e5d898d3a8..d93a572fa7f9 100644 --- a/seed/csharp-sdk/alias/src/SeedAlias/Core/Optional.cs +++ b/seed/csharp-sdk/alias/src/SeedAlias/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/alias/src/SeedAlias/Core/OptionalAttribute.cs b/seed/csharp-sdk/alias/src/SeedAlias/Core/OptionalAttribute.cs index 68b417382104..792d43bf0aeb 100644 --- a/seed/csharp-sdk/alias/src/SeedAlias/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/alias/src/SeedAlias/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedAlias.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/alias/src/SeedAlias/Core/QueryStringBuilder.cs b/seed/csharp-sdk/alias/src/SeedAlias/Core/QueryStringBuilder.cs index 0b9c952a047c..164db5d273ed 100644 --- a/seed/csharp-sdk/alias/src/SeedAlias/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/alias/src/SeedAlias/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/alias/src/SeedAlias/SeedAlias.csproj b/seed/csharp-sdk/alias/src/SeedAlias/SeedAlias.csproj index d8bf4fe5ab1a..bb549267341d 100644 --- a/seed/csharp-sdk/alias/src/SeedAlias/SeedAlias.csproj +++ b/seed/csharp-sdk/alias/src/SeedAlias/SeedAlias.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/alias/fern + https://github.com/alias/fern + git true diff --git a/seed/csharp-sdk/allof-inline/README.md b/seed/csharp-sdk/allof-inline/README.md index 838b7416734f..e5c311c96ff8 100644 --- a/seed/csharp-sdk/allof-inline/README.md +++ b/seed/csharp-sdk/allof-inline/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -122,7 +125,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreateRuleAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -135,7 +138,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreateRuleAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -165,7 +168,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreateRuleAsync(...); +var parsedData = await client.CreateRuleAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/allof-inline/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/allof-inline/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/allof-inline/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/allof-inline/src/SeedApi/SeedApi.csproj index 72bf657a0f91..69c62019e265 100644 --- a/seed/csharp-sdk/allof-inline/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/allof-inline/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/allof-inline/fern + https://github.com/allof-inline/fern + git true diff --git a/seed/csharp-sdk/allof/README.md b/seed/csharp-sdk/allof/README.md index 4e07988c7973..0e598aca44da 100644 --- a/seed/csharp-sdk/allof/README.md +++ b/seed/csharp-sdk/allof/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -122,7 +125,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreateRuleAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -135,7 +138,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreateRuleAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -165,7 +168,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreateRuleAsync(...); +var parsedData = await client.CreateRuleAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/allof/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/allof/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/allof/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/allof/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/allof/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/allof/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/allof/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/allof/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/allof/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/allof/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/allof/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/allof/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/allof/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/allof/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/allof/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/allof/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/allof/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/allof/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/allof/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/allof/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/allof/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/allof/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/allof/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/allof/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/allof/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/allof/src/SeedApi/SeedApi.csproj index f45281f7c5b1..171dfc112dd3 100644 --- a/seed/csharp-sdk/allof/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/allof/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/allof/fern + https://github.com/allof/fern + git true diff --git a/seed/csharp-sdk/any-auth/no-custom-config/README.md b/seed/csharp-sdk/any-auth/no-custom-config/README.md index 1fe31e98aa60..90ad0cf01908 100644 --- a/seed/csharp-sdk/any-auth/no-custom-config/README.md +++ b/seed/csharp-sdk/any-auth/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenAsync(...); +var parsedData = await client.Auth.GetTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs index b481743b3ae5..8b5797273cd9 100644 --- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Extensions.cs b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Extensions.cs index 6e2e34d6d4d6..a7b6539c5f76 100644 --- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Extensions.cs +++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/NullableAttribute.cs index d98ea4ad86dc..83713c9c4a6c 100644 --- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedAnyAuth.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedAnyAuth.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Optional.cs b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Optional.cs index ca15336eada1..0c12099c226f 100644 --- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Optional.cs +++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/OptionalAttribute.cs index 01fc91d6636f..3a7e688f98aa 100644 --- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedAnyAuth.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/QueryStringBuilder.cs index f079a14c6938..63dc4ef7e442 100644 --- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/SeedAnyAuth.csproj b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/SeedAnyAuth.csproj index 33da248f37c5..71d675291ed4 100644 --- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/SeedAnyAuth.csproj +++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/SeedAnyAuth.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/any-auth/fern + https://github.com/any-auth/fern + git true diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/README.md b/seed/csharp-sdk/any-auth/prefer-explicit-auth/README.md index 1fe31e98aa60..90ad0cf01908 100644 --- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/README.md +++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenAsync(...); +var parsedData = await client.Auth.GetTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs index b481743b3ae5..8b5797273cd9 100644 --- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Extensions.cs b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Extensions.cs index 6e2e34d6d4d6..a7b6539c5f76 100644 --- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Extensions.cs +++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/NullableAttribute.cs index d98ea4ad86dc..83713c9c4a6c 100644 --- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedAnyAuth.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedAnyAuth.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Optional.cs b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Optional.cs index ca15336eada1..0c12099c226f 100644 --- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Optional.cs +++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/OptionalAttribute.cs index 01fc91d6636f..3a7e688f98aa 100644 --- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedAnyAuth.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/QueryStringBuilder.cs index f079a14c6938..63dc4ef7e442 100644 --- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/SeedAnyAuth.csproj b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/SeedAnyAuth.csproj index 33da248f37c5..71d675291ed4 100644 --- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/SeedAnyAuth.csproj +++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/SeedAnyAuth.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/any-auth/fern + https://github.com/any-auth/fern + git true diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/README.md b/seed/csharp-sdk/api-wide-base-path-with-default/README.md index 562a6a80f3ac..93611b6ea44b 100644 --- a/seed/csharp-sdk/api-wide-base-path-with-default/README.md +++ b/seed/csharp-sdk/api-wide-base-path-with-default/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Widgets.CreateAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Widgets.CreateAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Widgets.CreateAsync(...); +var parsedData = await client.Widgets.CreateAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/SeedApi.csproj index 501c16187fc6..ceba29f259c3 100644 --- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/api-wide-base-path-with-default/fern + https://github.com/api-wide-base-path-with-default/fern + git true diff --git a/seed/csharp-sdk/api-wide-base-path/README.md b/seed/csharp-sdk/api-wide-base-path/README.md index 1c503d5c9343..e18103460829 100644 --- a/seed/csharp-sdk/api-wide-base-path/README.md +++ b/seed/csharp-sdk/api-wide-base-path/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.PostAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.PostAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.PostAsync(...); +var parsedData = await client.Service.PostAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath.Test/Utils/OptionalComparer.cs index 58a1f2e9f049..197ab07ffefa 100644 --- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Extensions.cs b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Extensions.cs index d247aa5e131d..a39a677248fa 100644 --- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Extensions.cs +++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/NullableAttribute.cs b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/NullableAttribute.cs index 0b5eab212195..8848f8cdc7c8 100644 --- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApiWideBasePath.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApiWideBasePath.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Optional.cs b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Optional.cs index e4f242f75502..ae2e14a0fd24 100644 --- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Optional.cs +++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/OptionalAttribute.cs b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/OptionalAttribute.cs index 93e5cce0086c..681804f39f93 100644 --- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApiWideBasePath.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/QueryStringBuilder.cs b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/QueryStringBuilder.cs index aee28fc7568b..b04f1b7c782c 100644 --- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/SeedApiWideBasePath.csproj b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/SeedApiWideBasePath.csproj index a37db4f16013..fe24c3169313 100644 --- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/SeedApiWideBasePath.csproj +++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/SeedApiWideBasePath.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/api-wide-base-path/fern + https://github.com/api-wide-base-path/fern + git true diff --git a/seed/csharp-sdk/audiences/README.md b/seed/csharp-sdk/audiences/README.md index e2388d0e53f1..1fc2fb4e1d66 100644 --- a/seed/csharp-sdk/audiences/README.md +++ b/seed/csharp-sdk/audiences/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -122,7 +125,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Foo.FindAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -135,7 +138,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Foo.FindAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -165,7 +168,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Foo.FindAsync(...); +var parsedData = await client.Foo.FindAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/audiences/src/SeedAudiences.Test/Utils/OptionalComparer.cs index 067674c0542e..656cfc247e89 100644 --- a/seed/csharp-sdk/audiences/src/SeedAudiences.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/audiences/src/SeedAudiences.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Extensions.cs b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Extensions.cs index 63b1bfb76838..10ec582111be 100644 --- a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Extensions.cs +++ b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/NullableAttribute.cs b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/NullableAttribute.cs index 2761d3bdbc11..3b2f52db0893 100644 --- a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedAudiences.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedAudiences.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Optional.cs b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Optional.cs index cb0d4e88e856..1ad60a4efa91 100644 --- a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Optional.cs +++ b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/OptionalAttribute.cs b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/OptionalAttribute.cs index 99ef51ffecf3..f7a508561149 100644 --- a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedAudiences.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/QueryStringBuilder.cs b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/QueryStringBuilder.cs index 51a497140c25..067849d758ea 100644 --- a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences/SeedAudiences.csproj b/seed/csharp-sdk/audiences/src/SeedAudiences/SeedAudiences.csproj index 9e31d759b50e..0e6f28ea5855 100644 --- a/seed/csharp-sdk/audiences/src/SeedAudiences/SeedAudiences.csproj +++ b/seed/csharp-sdk/audiences/src/SeedAudiences/SeedAudiences.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/audiences/fern + https://github.com/audiences/fern + git true diff --git a/seed/csharp-sdk/basic-auth-environment-variables/README.md b/seed/csharp-sdk/basic-auth-environment-variables/README.md index 8ca7dd80455b..d3a27e918f63 100644 --- a/seed/csharp-sdk/basic-auth-environment-variables/README.md +++ b/seed/csharp-sdk/basic-auth-environment-variables/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.BasicAuth.PostWithBasicAuthAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.BasicAuth.PostWithBasicAuthAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.BasicAuth.PostWithBasicAuthAsync(...); +var parsedData = await client.BasicAuth.PostWithBasicAuthAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables.Test/Utils/OptionalComparer.cs index d90b57b63c1f..e063c2f459bc 100644 --- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Extensions.cs b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Extensions.cs index 97cd783845d4..c0514cda70b8 100644 --- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Extensions.cs +++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/NullableAttribute.cs b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/NullableAttribute.cs index d573fb2ff908..9d0d6e643f48 100644 --- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedBasicAuthEnvironmentVariables.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedBasicAuthEnvironmentVariables.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Optional.cs b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Optional.cs index e40284dafe11..12ff55465be8 100644 --- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Optional.cs +++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/OptionalAttribute.cs b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/OptionalAttribute.cs index e90362425e91..b83c42ffc4e2 100644 --- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedBasicAuthEnvironmentVariables.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/QueryStringBuilder.cs b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/QueryStringBuilder.cs index e39124fd69a1..f5fb4ce1be0e 100644 --- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/SeedBasicAuthEnvironmentVariables.csproj b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/SeedBasicAuthEnvironmentVariables.csproj index 984b860aec31..762702b8d688 100644 --- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/SeedBasicAuthEnvironmentVariables.csproj +++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/SeedBasicAuthEnvironmentVariables.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/basic-auth-environment-variables/fern + https://github.com/basic-auth-environment-variables/fern + git true diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/README.md b/seed/csharp-sdk/basic-auth-pw-omitted/README.md index 43f9872f594f..b8b9f00ca5ac 100644 --- a/seed/csharp-sdk/basic-auth-pw-omitted/README.md +++ b/seed/csharp-sdk/basic-auth-pw-omitted/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.BasicAuth.PostWithBasicAuthAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.BasicAuth.PostWithBasicAuthAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.BasicAuth.PostWithBasicAuthAsync(...); +var parsedData = await client.BasicAuth.PostWithBasicAuthAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted.Test/Utils/OptionalComparer.cs index 740e356b0246..297fc8fca69a 100644 --- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Extensions.cs b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Extensions.cs index 8361264a88b1..aad9e8ac4e09 100644 --- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Extensions.cs +++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/NullableAttribute.cs b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/NullableAttribute.cs index 9355ac14b0df..83710a7c52be 100644 --- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedBasicAuthPwOmitted.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedBasicAuthPwOmitted.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Optional.cs b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Optional.cs index f165b4166582..3f26902cdce5 100644 --- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Optional.cs +++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/OptionalAttribute.cs b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/OptionalAttribute.cs index e5184234617c..e4d5488283b8 100644 --- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedBasicAuthPwOmitted.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/QueryStringBuilder.cs b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/QueryStringBuilder.cs index bd8ef83e2d7b..7fa2cee42f89 100644 --- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/SeedBasicAuthPwOmitted.csproj b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/SeedBasicAuthPwOmitted.csproj index 659e1108dc6e..0fb5180b72b1 100644 --- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/SeedBasicAuthPwOmitted.csproj +++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/SeedBasicAuthPwOmitted.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/basic-auth-pw-omitted/fern + https://github.com/basic-auth-pw-omitted/fern + git true diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/README.md b/seed/csharp-sdk/basic-auth/no-custom-config/README.md index 30db3ef25cee..975d3c256668 100644 --- a/seed/csharp-sdk/basic-auth/no-custom-config/README.md +++ b/seed/csharp-sdk/basic-auth/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.BasicAuth.PostWithBasicAuthAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.BasicAuth.PostWithBasicAuthAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.BasicAuth.PostWithBasicAuthAsync(...); +var parsedData = await client.BasicAuth.PostWithBasicAuthAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs index 529bd5841769..671e3c858c43 100644 --- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Extensions.cs b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Extensions.cs index b02b272a7bda..5b1bdb0d7dee 100644 --- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Extensions.cs +++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/NullableAttribute.cs index 7bce298d02f2..b4a967445efb 100644 --- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedBasicAuth.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedBasicAuth.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Optional.cs b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Optional.cs index f4ea51b459eb..8139e19a956e 100644 --- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Optional.cs +++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/OptionalAttribute.cs index 46a7d5a324c4..ca5a8509e750 100644 --- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedBasicAuth.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/QueryStringBuilder.cs index e2ce554def75..3c2e4f0aa7cb 100644 --- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/SeedBasicAuth.csproj b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/SeedBasicAuth.csproj index 0d2301bf46a3..01bfdaecef8e 100644 --- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/SeedBasicAuth.csproj +++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/SeedBasicAuth.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/basic-auth/fern + https://github.com/basic-auth/fern + git true diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/README.md b/seed/csharp-sdk/basic-auth/unified-client-options/README.md index a838c791d1d6..214266c0701d 100644 --- a/seed/csharp-sdk/basic-auth/unified-client-options/README.md +++ b/seed/csharp-sdk/basic-auth/unified-client-options/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -105,7 +108,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.BasicAuth.PostWithBasicAuthAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -118,7 +121,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.BasicAuth.PostWithBasicAuthAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -148,7 +151,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.BasicAuth.PostWithBasicAuthAsync(...); +var parsedData = await client.BasicAuth.PostWithBasicAuthAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs index 529bd5841769..671e3c858c43 100644 --- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Extensions.cs b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Extensions.cs index b02b272a7bda..5b1bdb0d7dee 100644 --- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Extensions.cs +++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/NullableAttribute.cs index 7bce298d02f2..b4a967445efb 100644 --- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedBasicAuth.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedBasicAuth.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Optional.cs b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Optional.cs index f4ea51b459eb..8139e19a956e 100644 --- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Optional.cs +++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/OptionalAttribute.cs index 46a7d5a324c4..ca5a8509e750 100644 --- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedBasicAuth.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/QueryStringBuilder.cs index e2ce554def75..3c2e4f0aa7cb 100644 --- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/SeedBasicAuth.csproj b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/SeedBasicAuth.csproj index 0d2301bf46a3..01bfdaecef8e 100644 --- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/SeedBasicAuth.csproj +++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/SeedBasicAuth.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/basic-auth/fern + https://github.com/basic-auth/fern + git true diff --git a/seed/csharp-sdk/basic-auth/wire-tests/README.md b/seed/csharp-sdk/basic-auth/wire-tests/README.md index 30db3ef25cee..975d3c256668 100644 --- a/seed/csharp-sdk/basic-auth/wire-tests/README.md +++ b/seed/csharp-sdk/basic-auth/wire-tests/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.BasicAuth.PostWithBasicAuthAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.BasicAuth.PostWithBasicAuthAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.BasicAuth.PostWithBasicAuthAsync(...); +var parsedData = await client.BasicAuth.PostWithBasicAuthAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs index 529bd5841769..671e3c858c43 100644 --- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Extensions.cs b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Extensions.cs index b02b272a7bda..5b1bdb0d7dee 100644 --- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Extensions.cs +++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/NullableAttribute.cs index 7bce298d02f2..b4a967445efb 100644 --- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedBasicAuth.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedBasicAuth.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Optional.cs b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Optional.cs index f4ea51b459eb..8139e19a956e 100644 --- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Optional.cs +++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/OptionalAttribute.cs index 46a7d5a324c4..ca5a8509e750 100644 --- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedBasicAuth.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/QueryStringBuilder.cs index e2ce554def75..3c2e4f0aa7cb 100644 --- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/SeedBasicAuth.csproj b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/SeedBasicAuth.csproj index 0d2301bf46a3..01bfdaecef8e 100644 --- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/SeedBasicAuth.csproj +++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/SeedBasicAuth.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/basic-auth/fern + https://github.com/basic-auth/fern + git true diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/README.md b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/README.md index 94acfc23b6d5..8a217956432e 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/README.md +++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.GetWithBearerTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.GetWithBearerTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.GetWithBearerTokenAsync(...); +var parsedData = await client.Service.GetWithBearerTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs index 2fef69c21dd9..4a30e997b631 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs index be56145f3b33..ce1a779daff3 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs index 746e89db4bba..d55c32c4307c 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedBearerTokenEnvironmentVariable.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedBearerTokenEnvironmentVariable.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs index a821e891e4df..315e861c38f5 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs index 055f52f78c95..38e60d1a36d7 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedBearerTokenEnvironmentVariable.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs index d5fd4e784eda..e3ebc329b797 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs @@ -87,6 +87,7 @@ internal ClientOptions Clone() Timeout = Timeout, Headers = new Headers(new Dictionary(Headers)), AdditionalHeaders = AdditionalHeaders, + Version = Version, }; } } diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs index 1339ae5a665a..63268abc22ec 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj index ac92b885f7ca..5a8e83564eb6 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj +++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/bearer-token-environment-variable/fern + https://github.com/bearer-token-environment-variable/fern + git true diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/README.md b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/README.md index 10c97d17b96a..080bf11c1282 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/README.md +++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.GetWithBearerTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.GetWithBearerTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.GetWithBearerTokenAsync(...); +var parsedData = await client.Service.GetWithBearerTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs index 2fef69c21dd9..4a30e997b631 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs index be56145f3b33..ce1a779daff3 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs index 746e89db4bba..d55c32c4307c 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedBearerTokenEnvironmentVariable.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedBearerTokenEnvironmentVariable.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs index a821e891e4df..315e861c38f5 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs index 055f52f78c95..38e60d1a36d7 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedBearerTokenEnvironmentVariable.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs index c2ccbdc5ff31..aa760d4142a9 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs @@ -17,6 +17,7 @@ internal ClientOptions(ClientOptions other) Timeout = other.Timeout; Headers = new Headers(new Dictionary(other.Headers)); AdditionalHeaders = other.AdditionalHeaders; + Version = other.Version; ApiKey = other.ApiKey; } diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs index 1339ae5a665a..63268abc22ec 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj index ac92b885f7ca..5a8e83564eb6 100644 --- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj +++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/bearer-token-environment-variable/fern + https://github.com/bearer-token-environment-variable/fern + git true diff --git a/seed/csharp-sdk/bytes-download/README.md b/seed/csharp-sdk/bytes-download/README.md index edeeae5f7132..e3fd9ebc81b4 100644 --- a/seed/csharp-sdk/bytes-download/README.md +++ b/seed/csharp-sdk/bytes-download/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.SimpleAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.SimpleAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.SimpleAsync(...); +var parsedData = await client.Service.SimpleAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload.Test/Utils/OptionalComparer.cs index 106ee59967e5..01eca6678cbc 100644 --- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Extensions.cs b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Extensions.cs index b9f6758307f6..33f3af6d63dc 100644 --- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Extensions.cs +++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/NullableAttribute.cs b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/NullableAttribute.cs index 23f6bf634614..017ea71fa9c0 100644 --- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedBytesDownload.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedBytesDownload.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Optional.cs b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Optional.cs index e7f71acad46e..9b523807dfd2 100644 --- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Optional.cs +++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/OptionalAttribute.cs b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/OptionalAttribute.cs index 7f0809999a58..48bbf03e7d44 100644 --- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedBytesDownload.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/QueryStringBuilder.cs b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/QueryStringBuilder.cs index 083b6dd63cca..0312825950b2 100644 --- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/SeedBytesDownload.csproj b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/SeedBytesDownload.csproj index 1cddf5921ab4..1475204f4575 100644 --- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/SeedBytesDownload.csproj +++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/SeedBytesDownload.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/bytes-download/fern + https://github.com/bytes-download/fern + git true diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload.Test/Utils/OptionalComparer.cs index 7d957f123a97..2906c452a810 100644 --- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Extensions.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Extensions.cs index c0cd651e604c..e31c158a6f84 100644 --- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Extensions.cs +++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/NullableAttribute.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/NullableAttribute.cs index f3b275daf6e6..566e50d17358 100644 --- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedBytesUpload.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedBytesUpload.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Optional.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Optional.cs index 3e14588bb222..359ed0bcc446 100644 --- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Optional.cs +++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/OptionalAttribute.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/OptionalAttribute.cs index 869393c741d5..43de186fc252 100644 --- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedBytesUpload.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/QueryStringBuilder.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/QueryStringBuilder.cs index 6372bc4b9dca..33ab582ada01 100644 --- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/SeedBytesUpload.csproj b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/SeedBytesUpload.csproj index 01517fa69151..4e668a36ab6f 100644 --- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/SeedBytesUpload.csproj +++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/SeedBytesUpload.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/bytes-upload/fern + https://github.com/bytes-upload/fern + git true diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Service/ServiceClient.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Service/ServiceClient.cs index 0d384dc567b4..badb80f3a234 100644 --- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Service/ServiceClient.cs +++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Service/ServiceClient.cs @@ -127,9 +127,6 @@ private async Task UploadWithQueryParamsAsyncCore( } } - /// - /// await client.Service.UploadAsync(new MemoryStream(Encoding.UTF8.GetBytes("[bytes]"))); - /// public WithRawResponseTask UploadAsync( Stream request, RequestOptions? options = null, @@ -139,11 +136,6 @@ public WithRawResponseTask UploadAsync( return new WithRawResponseTask(UploadAsyncCore(request, options, cancellationToken)); } - /// - /// await client.Service.UploadWithQueryParamsAsync( - /// new UploadWithQueryParamsRequest { Model = "nova-2" } - /// ); - /// public WithRawResponseTask UploadWithQueryParamsAsync( UploadWithQueryParamsRequest request, RequestOptions? options = null, diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Ast/Types/ContainerValue.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Ast/Types/ContainerValue.cs index aa38cc5bc2ab..eb16fd072fff 100644 --- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Ast/Types/ContainerValue.cs +++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Ast/Types/ContainerValue.cs @@ -58,7 +58,7 @@ public ContainerValue(ContainerValue.Optional value) public bool IsOptional => Type == "optional"; /// - /// Returns the value as a if is 'list', otherwise throws an exception. + /// Returns the value as a if is 'list', otherwise throws an exception. /// /// Thrown when is not 'list'. public IEnumerable AsList() => @@ -67,7 +67,7 @@ public IEnumerable AsList() => : throw new global::System.Exception("ContainerValue.Type is not 'list'"); /// - /// Returns the value as a if is 'optional', otherwise throws an exception. + /// Returns the value as a if is 'optional', otherwise throws an exception. /// /// Thrown when is not 'optional'. public FieldValue? AsOptional() => @@ -110,7 +110,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsList(out IEnumerable? value) { @@ -124,7 +124,7 @@ public bool TryAsList(out IEnumerable? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsOptional(out FieldValue? value) { diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/SeedApi.csproj index ce64f98ea32a..97a7dc929db5 100644 --- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/circular-references-advanced/fern + https://github.com/circular-references-advanced/fern + git true diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/circular-references-extends/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/circular-references-extends/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/circular-references-extends/src/SeedApi/SeedApi.csproj index fea32093da1c..61cee493e40c 100644 --- a/seed/csharp-sdk/circular-references-extends/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/circular-references-extends/fern + https://github.com/circular-references-extends/fern + git true diff --git a/seed/csharp-sdk/circular-references/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/circular-references/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/circular-references/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/circular-references/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/Ast/Types/ContainerValue.cs b/seed/csharp-sdk/circular-references/src/SeedApi/Ast/Types/ContainerValue.cs index aa38cc5bc2ab..eb16fd072fff 100644 --- a/seed/csharp-sdk/circular-references/src/SeedApi/Ast/Types/ContainerValue.cs +++ b/seed/csharp-sdk/circular-references/src/SeedApi/Ast/Types/ContainerValue.cs @@ -58,7 +58,7 @@ public ContainerValue(ContainerValue.Optional value) public bool IsOptional => Type == "optional"; /// - /// Returns the value as a if is 'list', otherwise throws an exception. + /// Returns the value as a if is 'list', otherwise throws an exception. /// /// Thrown when is not 'list'. public IEnumerable AsList() => @@ -67,7 +67,7 @@ public IEnumerable AsList() => : throw new global::System.Exception("ContainerValue.Type is not 'list'"); /// - /// Returns the value as a if is 'optional', otherwise throws an exception. + /// Returns the value as a if is 'optional', otherwise throws an exception. /// /// Thrown when is not 'optional'. public FieldValue? AsOptional() => @@ -110,7 +110,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsList(out IEnumerable? value) { @@ -124,7 +124,7 @@ public bool TryAsList(out IEnumerable? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsOptional(out FieldValue? value) { diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/circular-references/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/circular-references/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/circular-references/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/circular-references/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/circular-references/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/circular-references/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/circular-references/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/circular-references/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/circular-references/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/circular-references/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/circular-references/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/circular-references/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/circular-references/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/circular-references/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/circular-references/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/circular-references/src/SeedApi/SeedApi.csproj index c1c31c4be40b..5aca45084a95 100644 --- a/seed/csharp-sdk/circular-references/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/circular-references/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/circular-references/fern + https://github.com/circular-references/fern + git true diff --git a/seed/csharp-sdk/client-side-params/README.md b/seed/csharp-sdk/client-side-params/README.md index 8293b36b0154..a638dbfc02ca 100644 --- a/seed/csharp-sdk/client-side-params/README.md +++ b/seed/csharp-sdk/client-side-params/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.SearchResourcesAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.SearchResourcesAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.SearchResourcesAsync(...); +var parsedData = await client.Service.SearchResourcesAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams.Test/Utils/OptionalComparer.cs index f8e6183bb0ca..b191d0dcc69e 100644 --- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Extensions.cs b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Extensions.cs index e30ee9595307..be4421147b7b 100644 --- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Extensions.cs +++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/NullableAttribute.cs b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/NullableAttribute.cs index 2ba7f7d6c356..10498d8b396d 100644 --- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedClientSideParams.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedClientSideParams.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Optional.cs b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Optional.cs index c52ce95e4cba..fa5659ae74ef 100644 --- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Optional.cs +++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/OptionalAttribute.cs b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/OptionalAttribute.cs index 0a0869754ee7..15f2520398f3 100644 --- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedClientSideParams.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/QueryStringBuilder.cs b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/QueryStringBuilder.cs index 7375bb10e696..a34df3aefbd4 100644 --- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/SeedClientSideParams.csproj b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/SeedClientSideParams.csproj index dcd2a92ae1ee..475a3f5b1df3 100644 --- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/SeedClientSideParams.csproj +++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/SeedClientSideParams.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/client-side-params/fern + https://github.com/client-side-params/fern + git true diff --git a/seed/csharp-sdk/content-type/README.md b/seed/csharp-sdk/content-type/README.md index eac0ac505a34..46b02e755cb4 100644 --- a/seed/csharp-sdk/content-type/README.md +++ b/seed/csharp-sdk/content-type/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.PatchAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.PatchAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.PatchAsync(...); +var parsedData = await client.Service.PatchAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/content-type/src/SeedContentTypes.Test/Utils/OptionalComparer.cs index c412777769c7..eb5dae373a3d 100644 --- a/seed/csharp-sdk/content-type/src/SeedContentTypes.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/content-type/src/SeedContentTypes.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Extensions.cs b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Extensions.cs index 0c4cabccbdcf..47753c043726 100644 --- a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Extensions.cs +++ b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/NullableAttribute.cs b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/NullableAttribute.cs index 26873c5e7c5b..1414c3a72f9f 100644 --- a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedContentTypes.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedContentTypes.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Optional.cs b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Optional.cs index aa194ac4a2b3..ab8c87efdb90 100644 --- a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Optional.cs +++ b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/OptionalAttribute.cs b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/OptionalAttribute.cs index 8f70cd30ae2a..ced169b4056b 100644 --- a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedContentTypes.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/QueryStringBuilder.cs b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/QueryStringBuilder.cs index 88200476d04d..84572159efe4 100644 --- a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes/SeedContentTypes.csproj b/seed/csharp-sdk/content-type/src/SeedContentTypes/SeedContentTypes.csproj index 56d6d2d3cc78..e9df062b4764 100644 --- a/seed/csharp-sdk/content-type/src/SeedContentTypes/SeedContentTypes.csproj +++ b/seed/csharp-sdk/content-type/src/SeedContentTypes/SeedContentTypes.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/content-type/fern + https://github.com/content-type/fern + git true diff --git a/seed/csharp-sdk/cross-package-type-names/README.md b/seed/csharp-sdk/cross-package-type-names/README.md index 02ffcaf9d89d..02422f865886 100644 --- a/seed/csharp-sdk/cross-package-type-names/README.md +++ b/seed/csharp-sdk/cross-package-type-names/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -108,7 +111,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Foo.FindAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -121,7 +124,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Foo.FindAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -151,7 +154,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Foo.FindAsync(...); +var parsedData = await client.Foo.FindAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames.Test/Utils/OptionalComparer.cs index bad8767e61cb..846147ad9b56 100644 --- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Extensions.cs b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Extensions.cs index 5d451bf9cab9..2112f866b1c2 100644 --- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Extensions.cs +++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/NullableAttribute.cs b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/NullableAttribute.cs index 382797c8b543..9754e915bcfe 100644 --- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedCrossPackageTypeNames.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedCrossPackageTypeNames.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Optional.cs b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Optional.cs index 51387d737f25..a43e19f5db67 100644 --- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Optional.cs +++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/OptionalAttribute.cs b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/OptionalAttribute.cs index 2b7ab3d8e1d3..1b37020485df 100644 --- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedCrossPackageTypeNames.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/QueryStringBuilder.cs b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/QueryStringBuilder.cs index 60fbb47f80f2..780a9327e71b 100644 --- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/SeedCrossPackageTypeNames.csproj b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/SeedCrossPackageTypeNames.csproj index 863bca101206..812a9d474b86 100644 --- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/SeedCrossPackageTypeNames.csproj +++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/SeedCrossPackageTypeNames.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/cross-package-type-names/fern + https://github.com/cross-package-type-names/fern + git true diff --git a/seed/csharp-sdk/csharp-global-header-env/README.md b/seed/csharp-sdk/csharp-global-header-env/README.md index 583dc65535e2..dfa30c4822df 100644 --- a/seed/csharp-sdk/csharp-global-header-env/README.md +++ b/seed/csharp-sdk/csharp-global-header-env/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -42,7 +45,7 @@ Instantiate and use the client with the following: ```csharp using SeedCsharpGlobalHeaderEnv; -var client = new SeedCsharpGlobalHeaderEnvClient("USERNAME", "PASSWORD", "TOKEN", "VERSION"); +var client = new SeedCsharpGlobalHeaderEnvClient("USERNAME", "PASSWORD", "TOKEN", "2024-01-01"); await client.Service.GetWithApiVersionAsync(); ``` @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.GetWithApiVersionAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.GetWithApiVersionAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.GetWithApiVersionAsync(...); +var parsedData = await client.Service.GetWithApiVersionAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-global-header-env/snippet.json b/seed/csharp-sdk/csharp-global-header-env/snippet.json index a367f6a66aad..68abe9f12ba3 100644 --- a/seed/csharp-sdk/csharp-global-header-env/snippet.json +++ b/seed/csharp-sdk/csharp-global-header-env/snippet.json @@ -10,7 +10,7 @@ }, "snippet": { "type": "csharp", - "client": "using SeedCsharpGlobalHeaderEnv;\n\nvar client = new SeedCsharpGlobalHeaderEnvClient(\"USERNAME\", \"PASSWORD\", \"TOKEN\", \"VERSION\");\nawait client.Service.GetWithApiVersionAsync();\n" + "client": "using SeedCsharpGlobalHeaderEnv;\n\nvar client = new SeedCsharpGlobalHeaderEnvClient(\"USERNAME\", \"PASSWORD\", \"TOKEN\", \"2024-01-01\");\nawait client.Service.GetWithApiVersionAsync();\n" } } ] diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Unit/MockServer/BaseMockServerTest.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Unit/MockServer/BaseMockServerTest.cs index 2ed244fc69ff..b33af5f1749a 100644 --- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Unit/MockServer/BaseMockServerTest.cs +++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Unit/MockServer/BaseMockServerTest.cs @@ -27,7 +27,7 @@ public void GlobalSetup() "USERNAME", "PASSWORD", "TOKEN", - "VERSION", + "2024-01-01", clientOptions: new ClientOptions { BaseUrl = Server.Urls[0], MaxRetries = 0 } ); } diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Utils/OptionalComparer.cs index c641b2216ef9..fda74aec6fa0 100644 --- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Extensions.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Extensions.cs index 7394bec11d3d..86d193dd2d52 100644 --- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/NullableAttribute.cs index e9c387ed1753..d8fe59354026 100644 --- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedCsharpGlobalHeaderEnv.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedCsharpGlobalHeaderEnv.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Optional.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Optional.cs index 715ef60a27ee..c52cb8301009 100644 --- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/OptionalAttribute.cs index 6acff0a52c28..a8c9ee4cb57d 100644 --- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedCsharpGlobalHeaderEnv.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/QueryStringBuilder.cs index 228e2a2e4835..ea1112b7dfee 100644 --- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/SeedCsharpGlobalHeaderEnv.csproj b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/SeedCsharpGlobalHeaderEnv.csproj index 1133eb81104b..f9828b9bd966 100644 --- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/SeedCsharpGlobalHeaderEnv.csproj +++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/SeedCsharpGlobalHeaderEnv.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-global-header-env/fern + https://github.com/csharp-global-header-env/fern + git true diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/.fern/metadata.json b/seed/csharp-sdk/csharp-global-header-literal-env/.fern/metadata.json index b5663320f931..3274387319e1 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/.fern/metadata.json +++ b/seed/csharp-sdk/csharp-global-header-literal-env/.fern/metadata.json @@ -1,7 +1,7 @@ { "cliVersion": "DUMMY", "generatorName": "fernapi/fern-csharp-sdk", - "generatorVersion": "latest", + "generatorVersion": "local", "generatorConfig": {}, "originGitCommit": "DUMMY", "invokedBy": "manual", diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/README.md b/seed/csharp-sdk/csharp-global-header-literal-env/README.md index 40dc75ff7eb0..530379f8303e 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/README.md +++ b/seed/csharp-sdk/csharp-global-header-literal-env/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -42,7 +45,7 @@ Instantiate and use the client with the following: ```csharp using SeedCsharpGlobalHeaderLiteralEnv; -var client = new SeedCsharpGlobalHeaderLiteralEnvClient("TOKEN", "VERSION"); +var client = new SeedCsharpGlobalHeaderLiteralEnvClient("TOKEN", "2026-07-15"); await client.Service.GetWithLiteralVersionHeaderAsync(); ``` @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.GetWithLiteralVersionHeaderAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.GetWithLiteralVersionHeaderAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.GetWithLiteralVersionHeaderAsync(...); +var parsedData = await client.Service.GetWithLiteralVersionHeaderAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/snippet.json b/seed/csharp-sdk/csharp-global-header-literal-env/snippet.json index f67064e52131..227455777e18 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/snippet.json +++ b/seed/csharp-sdk/csharp-global-header-literal-env/snippet.json @@ -10,7 +10,7 @@ }, "snippet": { "type": "csharp", - "client": "using SeedCsharpGlobalHeaderLiteralEnv;\n\nvar client = new SeedCsharpGlobalHeaderLiteralEnvClient(\"TOKEN\", \"VERSION\");\nawait client.Service.GetWithLiteralVersionHeaderAsync();\n" + "client": "using SeedCsharpGlobalHeaderLiteralEnv;\n\nvar client = new SeedCsharpGlobalHeaderLiteralEnvClient(\"TOKEN\", \"2026-07-15\");\nawait client.Service.GetWithLiteralVersionHeaderAsync();\n" } } ] diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Unit/MockServer/BaseMockServerTest.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Unit/MockServer/BaseMockServerTest.cs index 7bc4f19c7278..bbdc8684c494 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Unit/MockServer/BaseMockServerTest.cs +++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Unit/MockServer/BaseMockServerTest.cs @@ -25,7 +25,7 @@ public void GlobalSetup() // Initialize the Client Client = new SeedCsharpGlobalHeaderLiteralEnvClient( "TOKEN", - "VERSION", + "2026-07-15", clientOptions: new ClientOptions { BaseUrl = Server.Urls[0], MaxRetries = 0 } ); } diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Utils/OptionalComparer.cs index aae731a5dbda..6c5135068429 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Extensions.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Extensions.cs index 7cd2007ffd45..fd400930ea93 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/NullableAttribute.cs index 59ff381d876b..1f050b791961 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedCsharpGlobalHeaderLiteralEnv.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedCsharpGlobalHeaderLiteralEnv.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Optional.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Optional.cs index 5e787718c8ae..e81285ed85bb 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/OptionalAttribute.cs index 62992a73fd7f..45bad46de719 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedCsharpGlobalHeaderLiteralEnv.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Public/ClientOptions.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Public/ClientOptions.cs index 93670833fa80..b05143ddf178 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Public/ClientOptions.cs +++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Public/ClientOptions.cs @@ -87,6 +87,7 @@ internal ClientOptions Clone() Timeout = Timeout, Headers = new Headers(new Dictionary(Headers)), AdditionalHeaders = AdditionalHeaders, + Version = Version, }; } } diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/QueryStringBuilder.cs index fb8cd80a4628..1db3740134cf 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnv.csproj b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnv.csproj index 9cdd222e57e3..9443d281dc0a 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnv.csproj +++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnv.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-global-header-literal-env/fern + https://github.com/csharp-global-header-literal-env/fern + git true diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnvClient.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnvClient.cs index eed293756061..a735a138b540 100644 --- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnvClient.cs +++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnvClient.cs @@ -17,6 +17,7 @@ public SeedCsharpGlobalHeaderLiteralEnvClient( "SQUARE_TOKEN", "Please pass in token or set the environment variable SQUARE_TOKEN." ); + Version ??= clientOptions?.Version; Version ??= Environment.GetEnvironmentVariable("VERSION") ?? "2026-07-15"; clientOptions ??= new ClientOptions(); var platformHeaders = new Headers( diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/README.md b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/README.md index 27e3fbd8ae14..bfd62ad7f569 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/README.md +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/README.md @@ -23,6 +23,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -113,7 +116,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.DataService.CheckAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -126,7 +129,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.DataService.CheckAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/SeedApi.csproj index f108be921720..aec58e39115a 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-grpc-proto-exhaustive/fern + https://github.com/csharp-grpc-proto-exhaustive/fern + git true diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/README.md b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/README.md index 27e3fbd8ae14..bfd62ad7f569 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/README.md +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/README.md @@ -23,6 +23,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -113,7 +116,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.DataService.CheckAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -126,7 +129,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.DataService.CheckAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/SeedApi.csproj index f108be921720..aec58e39115a 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-grpc-proto-exhaustive/fern + https://github.com/csharp-grpc-proto-exhaustive/fern + git true diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/README.md b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/README.md index 27e3fbd8ae14..bfd62ad7f569 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/README.md +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/README.md @@ -23,6 +23,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -113,7 +116,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.DataService.CheckAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -126,7 +129,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.DataService.CheckAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/SeedApi.csproj index 78043dc7d01e..2fd4816c690d 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/SeedApi.csproj @@ -9,7 +9,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-grpc-proto-exhaustive/fern + https://github.com/csharp-grpc-proto-exhaustive/fern + git true diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/README.md b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/README.md index 27e3fbd8ae14..bfd62ad7f569 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/README.md +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/README.md @@ -23,6 +23,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -113,7 +116,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.DataService.CheckAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -126,7 +129,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.DataService.CheckAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/SeedApi.csproj index f108be921720..aec58e39115a 100644 --- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-grpc-proto-exhaustive/fern + https://github.com/csharp-grpc-proto-exhaustive/fern + git true diff --git a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/README.md b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/README.md index 328b5da57f53..353707e4a776 100644 --- a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/README.md +++ b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/README.md @@ -21,6 +21,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -98,7 +101,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.UserService.CreateAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -111,7 +114,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.UserService.CreateAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` diff --git a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/SeedApi.csproj index 058870cd882e..1b2bde1b8d23 100644 --- a/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/csharp-grpc-proto/no-custom-config/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-grpc-proto/fern + https://github.com/csharp-grpc-proto/fern + git true diff --git a/seed/csharp-sdk/csharp-inline-types/inline-types/README.md b/seed/csharp-sdk/csharp-inline-types/inline-types/README.md index a19f4b8d9aca..9bd33a73fca3 100644 --- a/seed/csharp-sdk/csharp-inline-types/inline-types/README.md +++ b/seed/csharp-sdk/csharp-inline-types/inline-types/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -108,7 +111,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetRootAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -121,7 +124,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetRootAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -151,7 +154,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetRootAsync(...); +var parsedData = await client.GetRootAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject.Test/Utils/OptionalComparer.cs index cc24ed83b13d..35722da95f75 100644 --- a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/Extensions.cs b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/Extensions.cs index f1b0f52b6193..201231905e6a 100644 --- a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/NullableAttribute.cs index d04139e265f6..a306f72516ee 100644 --- a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedObject.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedObject.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/Optional.cs b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/Optional.cs index ac97764fc8b4..46e6d01a74e0 100644 --- a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/OptionalAttribute.cs index c74fcf21c2ff..6655c6ea4e76 100644 --- a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedObject.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/QueryStringBuilder.cs index fc73bd7f39ad..33b8c3ee48e6 100644 --- a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/SeedObject.csproj b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/SeedObject.csproj index 7c6a6e274437..f0cf37507d1e 100644 --- a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/SeedObject.csproj +++ b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/SeedObject.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-inline-types/fern + https://github.com/csharp-inline-types/fern + git true diff --git a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Types/UnionTypeWithAliasListVariant.cs b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Types/UnionTypeWithAliasListVariant.cs index 9225e7badfc6..26ed28d43a9d 100644 --- a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Types/UnionTypeWithAliasListVariant.cs +++ b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Types/UnionTypeWithAliasListVariant.cs @@ -44,7 +44,7 @@ public UnionTypeWithAliasListVariant(UnionTypeWithAliasListVariant.AliasVariant public bool IsAliasVariant => Type == "aliasVariant"; /// - /// Returns the value as a if is 'aliasVariant', otherwise throws an exception. + /// Returns the value as a if is 'aliasVariant', otherwise throws an exception. /// /// Thrown when is not 'aliasVariant'. public IEnumerable AsAliasVariant() => @@ -83,7 +83,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsAliasVariant(out IEnumerable? value) { diff --git a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Types/UnionTypeWithAliasMapVariant.cs b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Types/UnionTypeWithAliasMapVariant.cs index 34ea646018d6..c2db5c043bbb 100644 --- a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Types/UnionTypeWithAliasMapVariant.cs +++ b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Types/UnionTypeWithAliasMapVariant.cs @@ -44,7 +44,7 @@ public UnionTypeWithAliasMapVariant(UnionTypeWithAliasMapVariant.AliasVariant va public bool IsAliasVariant => Type == "aliasVariant"; /// - /// Returns the value as a if is 'aliasVariant', otherwise throws an exception. + /// Returns the value as a if is 'aliasVariant', otherwise throws an exception. /// /// Thrown when is not 'aliasVariant'. public Dictionary AsAliasVariant() => @@ -83,7 +83,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsAliasVariant(out Dictionary? value) { diff --git a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Types/UnionTypeWithAliasSetVariant.cs b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Types/UnionTypeWithAliasSetVariant.cs index 34e57248d6dc..6ac4a442a73f 100644 --- a/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Types/UnionTypeWithAliasSetVariant.cs +++ b/seed/csharp-sdk/csharp-inline-types/inline-types/src/SeedObject/Types/UnionTypeWithAliasSetVariant.cs @@ -44,7 +44,7 @@ public UnionTypeWithAliasSetVariant(UnionTypeWithAliasSetVariant.AliasVariant va public bool IsAliasVariant => Type == "aliasVariant"; /// - /// Returns the value as a if is 'aliasVariant', otherwise throws an exception. + /// Returns the value as a if is 'aliasVariant', otherwise throws an exception. /// /// Thrown when is not 'aliasVariant'. public HashSet AsAliasVariant() => @@ -83,7 +83,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsAliasVariant(out HashSet? value) { diff --git a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/README.md b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/README.md index d89ab428a236..726961e6a262 100644 --- a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/README.md +++ b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenAsync(...); +var parsedData = await client.Auth.GetTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/SeedApi.csproj index 9da43d3ad543..1d0d330a0dcd 100644 --- a/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/csharp-multi-env-url-templating/no-custom-config/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-multi-env-url-templating/fern + https://github.com/csharp-multi-env-url-templating/fern + git true diff --git a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/README.md b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/README.md index c94f9a23114c..4ac2ed1fbfd4 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/README.md +++ b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreateUserAsync(...); +var parsedData = await client.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net.Test/Utils/OptionalComparer.cs index 9953ff9378d3..d6e3f999ab94 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Contoso.Net.csproj b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Contoso.Net.csproj index 30855c3694ed..f110ae4d31d5 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Contoso.Net.csproj +++ b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Contoso.Net.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-namespace-collision/fern + https://github.com/csharp-namespace-collision/fern + git true diff --git a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/Extensions.cs b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/Extensions.cs index ae342c6f96fb..20538e977c9e 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/NullableAttribute.cs index c492c4f39c07..3e680e97dafa 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace Contoso.Net.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace Contoso.Net.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/Optional.cs b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/Optional.cs index a451fdd4d35e..8b2af60c52ba 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/OptionalAttribute.cs index b92a5d34444c..39f4674bc8af 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace Contoso.Net.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/QueryStringBuilder.cs index ed0d12140ef2..ea6ab923d158 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/explicit-namespaces/src/Contoso.Net/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/README.md b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/README.md index d9b824d38f61..c2e4e48923c6 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/README.md +++ b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreateUserAsync(...); +var parsedData = await client.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision.Test/Utils/OptionalComparer.cs index 520fac05ff16..df81b1080ea3 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/Extensions.cs b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/Extensions.cs index 7392418ec9aa..897451685f2e 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/NullableAttribute.cs index d1f4c76b5acc..bb1c79f67a12 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedCsharpNamespaceCollision.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedCsharpNamespaceCollision.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : Attribute { } diff --git a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/Optional.cs b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/Optional.cs index 7a9ba206c684..e26a8d18494d 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/OptionalAttribute.cs index 15f1535789bd..df951f21cf40 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedCsharpNamespaceCollision.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : Attribute { } diff --git a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/QueryStringBuilder.cs index 6b6f5f6249ac..ebafaee40adc 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/SeedCsharpNamespaceCollision.csproj b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/SeedCsharpNamespaceCollision.csproj index cd301671e69f..22c49392a5e3 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/SeedCsharpNamespaceCollision.csproj +++ b/seed/csharp-sdk/csharp-namespace-collision/fully-qualified-namespaces/src/SeedCsharpNamespaceCollision/SeedCsharpNamespaceCollision.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-namespace-collision/fern + https://github.com/csharp-namespace-collision/fern + git true diff --git a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/README.md b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/README.md index c94f9a23114c..4ac2ed1fbfd4 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/README.md +++ b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreateUserAsync(...); +var parsedData = await client.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net.Test/Utils/OptionalComparer.cs index 9953ff9378d3..d6e3f999ab94 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Contoso.Net.csproj b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Contoso.Net.csproj index 30855c3694ed..f110ae4d31d5 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Contoso.Net.csproj +++ b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Contoso.Net.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-namespace-collision/fern + https://github.com/csharp-namespace-collision/fern + git true diff --git a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/Extensions.cs b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/Extensions.cs index ae342c6f96fb..20538e977c9e 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/NullableAttribute.cs index c492c4f39c07..3e680e97dafa 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace Contoso.Net.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace Contoso.Net.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/Optional.cs b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/Optional.cs index a451fdd4d35e..8b2af60c52ba 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/OptionalAttribute.cs index b92a5d34444c..39f4674bc8af 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace Contoso.Net.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/QueryStringBuilder.cs index ed0d12140ef2..ea6ab923d158 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/namespace-client-collision/src/Contoso.Net/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/README.md b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/README.md index b31095b15a99..2ccafcdab13c 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/README.md +++ b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreateUserAsync(...); +var parsedData = await client.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net.Test/Utils/OptionalComparer.cs index 6a24fc4368c1..6291d439960e 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Contoso.Net.csproj b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Contoso.Net.csproj index 30855c3694ed..f110ae4d31d5 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Contoso.Net.csproj +++ b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Contoso.Net.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-namespace-collision/fern + https://github.com/csharp-namespace-collision/fern + git true diff --git a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/Extensions.cs b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/Extensions.cs index ae342c6f96fb..20538e977c9e 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/NullableAttribute.cs index c492c4f39c07..3e680e97dafa 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace Contoso.Net.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace Contoso.Net.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/Optional.cs b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/Optional.cs index a451fdd4d35e..8b2af60c52ba 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/OptionalAttribute.cs index b92a5d34444c..39f4674bc8af 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace Contoso.Net.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/QueryStringBuilder.cs index ed0d12140ef2..ea6ab923d158 100644 --- a/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-namespace-collision/no-client-namespace-match/src/Contoso.Net/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/README.md b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/README.md index cbce2bafea9b..8aca1da51c4a 100644 --- a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/README.md +++ b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Tasktest.HelloAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Tasktest.HelloAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Tasktest.HelloAsync(...); +var parsedData = await client.Tasktest.HelloAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict.Test/Utils/OptionalComparer.cs index 6c78567c64ac..c260589432ad 100644 --- a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/Extensions.cs b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/Extensions.cs index 18a9f20a38f2..a498e148fc32 100644 --- a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/NullableAttribute.cs index 1b8c9ca6f0b2..f44d3dae847b 100644 --- a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace Seed.CsharpNamespaceConflict.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace Seed.CsharpNamespaceConflict.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/Optional.cs b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/Optional.cs index 26dbc0987d33..7ff3dee31c59 100644 --- a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/OptionalAttribute.cs index a1ba2467d065..c31f6559741a 100644 --- a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace Seed.CsharpNamespaceConflict.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/QueryStringBuilder.cs index 687bb114ac09..0e88b221e9c4 100644 --- a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Seed.CsharpNamespaceConflict.csproj b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Seed.CsharpNamespaceConflict.csproj index aa187f6869e0..1da6df47539d 100644 --- a/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Seed.CsharpNamespaceConflict.csproj +++ b/seed/csharp-sdk/csharp-namespace-conflict/client-class-name-matches-namespace-root/src/Seed.CsharpNamespaceConflict/Seed.CsharpNamespaceConflict.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-namespace-conflict/fern + https://github.com/csharp-namespace-conflict/fern + git true diff --git a/seed/csharp-sdk/csharp-oauth-token-optional/README.md b/seed/csharp-sdk/csharp-oauth-token-optional/README.md index f30904b3b07a..67bab19b4c91 100644 --- a/seed/csharp-sdk/csharp-oauth-token-optional/README.md +++ b/seed/csharp-sdk/csharp-oauth-token-optional/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -108,7 +111,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.CreateOauth2TokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -121,7 +124,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.CreateOauth2TokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -151,7 +154,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.CreateOauth2TokenAsync(...); +var parsedData = await client.Auth.CreateOauth2TokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional.Test/Utils/OptionalComparer.cs index 8307bf363d49..7f747325609a 100644 --- a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/Extensions.cs b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/Extensions.cs index 46d35ce57318..3aeda744425a 100644 --- a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/NullableAttribute.cs index b3022e92298e..69936676b88b 100644 --- a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedCsharpOauthTokenOptional.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedCsharpOauthTokenOptional.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/Optional.cs b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/Optional.cs index e134fcb8b3b4..8bf5e2f8a2cb 100644 --- a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/OptionalAttribute.cs index 669a01b8d3ac..b2665036e9e4 100644 --- a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedCsharpOauthTokenOptional.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/QueryStringBuilder.cs index e55e4da7663a..43e20dcfa504 100644 --- a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/SeedCsharpOauthTokenOptional.csproj b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/SeedCsharpOauthTokenOptional.csproj index 10847fbad89e..300ddc797f64 100644 --- a/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/SeedCsharpOauthTokenOptional.csproj +++ b/seed/csharp-sdk/csharp-oauth-token-optional/src/SeedCsharpOauthTokenOptional/SeedCsharpOauthTokenOptional.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-oauth-token-optional/fern + https://github.com/csharp-oauth-token-optional/fern + git true diff --git a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/README.md b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/README.md index 1331ed8a6c1c..1b69923b3051 100644 --- a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/README.md +++ b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.SetApprovedBillAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.SetApprovedBillAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.SetApprovedBillAsync(...); +var parsedData = await client.SetApprovedBillAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder.Test/Utils/OptionalComparer.cs index 8109f0ab7de7..6a63747a987d 100644 --- a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/Extensions.cs b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/Extensions.cs index 5957e8683c8b..620bf57aed52 100644 --- a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/NullableAttribute.cs index ba4cc8e75e7f..347ffefe3350 100644 --- a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedCsharpPathParamOrder.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedCsharpPathParamOrder.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/Optional.cs b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/Optional.cs index 211b02dc0624..92962940fa19 100644 --- a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/OptionalAttribute.cs index 067ef2eccea7..929c7850c3d7 100644 --- a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedCsharpPathParamOrder.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/QueryStringBuilder.cs index 611eecff3ccc..a4f01b334dce 100644 --- a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/SeedCsharpPathParamOrder.csproj b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/SeedCsharpPathParamOrder.csproj index 3be7d9061d1e..229e3073dc2c 100644 --- a/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/SeedCsharpPathParamOrder.csproj +++ b/seed/csharp-sdk/csharp-path-param-order/no-custom-config/src/SeedCsharpPathParamOrder/SeedCsharpPathParamOrder.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-path-param-order/fern + https://github.com/csharp-path-param-order/fern + git true diff --git a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/README.md b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/README.md index 629e96df8486..9fa96b0a1249 100644 --- a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/README.md +++ b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client._.CreateCatalogAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client._.CreateCatalogAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client._.CreateCatalogAsync(...); +var parsedData = await client._.CreateCatalogAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/SeedApi.csproj index 133e7c36f768..4e971f9252b1 100644 --- a/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/csharp-property-name-collision/no-custom-config/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-property-name-collision/fern + https://github.com/csharp-property-name-collision/fern + git true diff --git a/seed/csharp-sdk/csharp-readonly-request/README.md b/seed/csharp-sdk/csharp-readonly-request/README.md index 159c6c9543c5..987bb6baac40 100644 --- a/seed/csharp-sdk/csharp-readonly-request/README.md +++ b/seed/csharp-sdk/csharp-readonly-request/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -118,7 +121,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.BatchCreateAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -131,7 +134,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.BatchCreateAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -161,7 +164,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.BatchCreateAsync(...); +var parsedData = await client.BatchCreateAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest.Test/Utils/OptionalComparer.cs index 27ee64b90005..ca49668bcd0e 100644 --- a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/Extensions.cs b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/Extensions.cs index 7294a63d488d..6da6a32c7595 100644 --- a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/NullableAttribute.cs index be4888479d0d..3a8e850ba13c 100644 --- a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedCsharpReadonlyRequest.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedCsharpReadonlyRequest.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/Optional.cs b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/Optional.cs index 4f980cf674e1..a53be6b48d1f 100644 --- a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/OptionalAttribute.cs index 778ed4794206..b999b4d3ea6e 100644 --- a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedCsharpReadonlyRequest.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/QueryStringBuilder.cs index 2290839c8c98..6acd4ac360e2 100644 --- a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/SeedCsharpReadonlyRequest.csproj b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/SeedCsharpReadonlyRequest.csproj index 16b5f1e713ec..462ad8fbe049 100644 --- a/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/SeedCsharpReadonlyRequest.csproj +++ b/seed/csharp-sdk/csharp-readonly-request/src/SeedCsharpReadonlyRequest/SeedCsharpReadonlyRequest.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-readonly-request/fern + https://github.com/csharp-readonly-request/fern + git true diff --git a/seed/csharp-sdk/csharp-system-collision/system-client/README.md b/seed/csharp-sdk/csharp-system-collision/system-client/README.md index 45141d0fa665..d69db319dc0a 100644 --- a/seed/csharp-sdk/csharp-system-collision/system-client/README.md +++ b/seed/csharp-sdk/csharp-system-collision/system-client/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -111,7 +114,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -124,7 +127,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -154,7 +157,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreateUserAsync(...); +var parsedData = await client.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision.Test/Utils/OptionalComparer.cs index 98f264b00db7..828a17532929 100644 --- a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/Extensions.cs b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/Extensions.cs index 7eccd989d47a..47f95a02b054 100644 --- a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/NullableAttribute.cs index 6a5a0555d950..ea3926775e34 100644 --- a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedCsharpSystemCollision.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedCsharpSystemCollision.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/Optional.cs b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/Optional.cs index 7e9b1eda8d0b..46ce7bd693cd 100644 --- a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/OptionalAttribute.cs index 9e4e771aa8b9..51a666d22daa 100644 --- a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedCsharpSystemCollision.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/QueryStringBuilder.cs index 0fdae79ee61a..915ea4b3d060 100644 --- a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/SeedCsharpSystemCollision.csproj b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/SeedCsharpSystemCollision.csproj index 76c1a6be880c..2a716a0f1760 100644 --- a/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/SeedCsharpSystemCollision.csproj +++ b/seed/csharp-sdk/csharp-system-collision/system-client/src/SeedCsharpSystemCollision/SeedCsharpSystemCollision.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-system-collision/fern + https://github.com/csharp-system-collision/fern + git true diff --git a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/README.md b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/README.md index 8263f5721e03..06c08634b4ba 100644 --- a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/README.md +++ b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -107,7 +110,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreateAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -120,7 +123,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreateAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -150,7 +153,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreateAsync(...); +var parsedData = await client.CreateAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties.Test/Utils/OptionalComparer.cs index b3d02d68e6f6..39a9cb42591d 100644 --- a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/Extensions.cs b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/Extensions.cs index 53bf82573ea4..2dd5784405a8 100644 --- a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/NullableAttribute.cs index a18229dc2210..c286fbca2d23 100644 --- a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedCsharpUnionBaseProperties.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedCsharpUnionBaseProperties.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/Optional.cs b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/Optional.cs index 5396428a41ad..f871dfa5204d 100644 --- a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/OptionalAttribute.cs index dc2faa9fca0f..daf49a3a6c11 100644 --- a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedCsharpUnionBaseProperties.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/QueryStringBuilder.cs index 46d057d242c7..a2f379d6b0a2 100644 --- a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/SeedCsharpUnionBaseProperties.csproj b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/SeedCsharpUnionBaseProperties.csproj index 3c95806c5e6b..2cdea79e5184 100644 --- a/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/SeedCsharpUnionBaseProperties.csproj +++ b/seed/csharp-sdk/csharp-union-base-properties/dedupe-union-base-properties/src/SeedCsharpUnionBaseProperties/SeedCsharpUnionBaseProperties.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-union-base-properties/fern + https://github.com/csharp-union-base-properties/fern + git true diff --git a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/README.md b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/README.md index cf7ee535c478..271b5329326b 100644 --- a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/README.md +++ b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetTimeZoneAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetTimeZoneAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetTimeZoneAsync(...); +var parsedData = await client.GetTimeZoneAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities.Test/Unit/MockServer/GetTimeZoneTest.cs b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities.Test/Unit/MockServer/GetTimeZoneTest.cs index ce22831b6a0c..c960b7457afa 100644 --- a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities.Test/Unit/MockServer/GetTimeZoneTest.cs +++ b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities.Test/Unit/MockServer/GetTimeZoneTest.cs @@ -15,7 +15,9 @@ public async Task MockServerTest() "timeZoneOffset": "timeZoneOffset", "mathExpression": "mathExpression", "validEntity": "validEntity", - "specialChars": "specialChars" + "specialChars": "specialChars", + "documentationLink": "documentationLink", + "escapedDocumentationLink": "escapedDocumentationLink" } """; diff --git a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities.Test/Utils/OptionalComparer.cs index 503ad1e20af7..3cd4bd8ae2f8 100644 --- a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/Extensions.cs b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/Extensions.cs index ffa69979e450..dba70c9670ae 100644 --- a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/Extensions.cs +++ b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/NullableAttribute.cs index f3233be792fb..4f8c34c7dcd3 100644 --- a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedCsharpXmlEntities.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedCsharpXmlEntities.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/Optional.cs b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/Optional.cs index e1d22b2966aa..2643c552ec69 100644 --- a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/Optional.cs +++ b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/OptionalAttribute.cs index 97d7d5eb7666..00570d0f4680 100644 --- a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedCsharpXmlEntities.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/QueryStringBuilder.cs index 3ab0487e0c4b..1bd6d3fb9c78 100644 --- a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj index d95f0c4517b1..0a5dad18f0b4 100644 --- a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj +++ b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/csharp-xml-entities/fern + https://github.com/csharp-xml-entities/fern + git true diff --git a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Types/TimeZoneModel.cs b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Types/TimeZoneModel.cs index 2756ef1f3959..c1a59a67ff35 100644 --- a/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Types/TimeZoneModel.cs +++ b/seed/csharp-sdk/csharp-xml-entities/no-custom-config/src/SeedCsharpXmlEntities/Types/TimeZoneModel.cs @@ -39,6 +39,18 @@ public record TimeZoneModel : IJsonOnDeserialized [JsonPropertyName("specialChars")] public string? SpecialChars { get; set; } + /// + /// See see here for details + /// + [JsonPropertyName("documentationLink")] + public string? DocumentationLink { get; set; } + + /// + /// See see here for details + /// + [JsonPropertyName("escapedDocumentationLink")] + public string? EscapedDocumentationLink { get; set; } + [JsonIgnore] public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.editorconfig b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.editorconfig new file mode 100644 index 000000000000..1e7a0adbac80 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.editorconfig @@ -0,0 +1,35 @@ +root = true + +[*.cs] +resharper_arrange_object_creation_when_type_evident_highlighting = hint +resharper_auto_property_can_be_made_get_only_global_highlighting = hint +resharper_check_namespace_highlighting = hint +resharper_class_never_instantiated_global_highlighting = hint +resharper_class_never_instantiated_local_highlighting = hint +resharper_collection_never_updated_global_highlighting = hint +resharper_convert_type_check_pattern_to_null_check_highlighting = hint +resharper_inconsistent_naming_highlighting = hint +resharper_member_can_be_private_global_highlighting = hint +resharper_member_hides_static_from_outer_class_highlighting = hint +resharper_not_accessed_field_local_highlighting = hint +resharper_nullable_warning_suppression_is_used_highlighting = suggestion +resharper_partial_type_with_single_part_highlighting = hint +resharper_prefer_concrete_value_over_default_highlighting = none +resharper_private_field_can_be_converted_to_local_variable_highlighting = hint +resharper_property_can_be_made_init_only_global_highlighting = hint +resharper_property_can_be_made_init_only_local_highlighting = hint +resharper_redundant_name_qualifier_highlighting = none +resharper_redundant_using_directive_highlighting = hint +resharper_replace_slice_with_range_indexer_highlighting = none +resharper_unused_auto_property_accessor_global_highlighting = hint +resharper_unused_auto_property_accessor_local_highlighting = hint +resharper_unused_member_global_highlighting = hint +resharper_unused_type_global_highlighting = hint +resharper_use_string_interpolation_highlighting = hint +dotnet_diagnostic.CS1591.severity = suggestion + +[src/**/Types/*.cs] +resharper_check_namespace_highlighting = none + +[src/**/Core/Public/*.cs] +resharper_check_namespace_highlighting = none \ No newline at end of file diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.fern/metadata.json b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.fern/metadata.json new file mode 100644 index 000000000000..8b3516fa48cf --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.fern/metadata.json @@ -0,0 +1,12 @@ +{ + "cliVersion": "DUMMY", + "generatorName": "fernapi/fern-csharp-sdk", + "generatorVersion": "local", + "generatorConfig": { + "generate-documentation-file": false + }, + "originGitCommit": "DUMMY", + "invokedBy": "manual", + "requestedVersion": "0.0.1", + "sdkVersion": "0.0.1" +} \ No newline at end of file diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.github/workflows/ci.yml b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.github/workflows/ci.yml new file mode 100644 index 000000000000..162400395053 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.github/workflows/ci.yml @@ -0,0 +1,51 @@ +name: ci + +on: [push] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +env: + DOTNET_NOLOGO: true + +jobs: + ci: + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v6 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.x + + - name: Install tools + run: dotnet tool restore + + - name: Restore dependencies + run: dotnet restore src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj + + - name: Build + run: dotnet build src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj --no-restore -c Release + + - name: Restore test dependencies + run: dotnet restore src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj + + - name: Build tests + run: dotnet build src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj --no-restore -c Release + + - name: Test + run: dotnet test src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj --no-restore --no-build -c Release + + - name: Pack + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + run: dotnet pack src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj --no-build --no-restore -c Release + + - name: Publish to NuGet.org + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_TOKEN }} + run: dotnet nuget push src/SeedCsharpXmlEntities/bin/Release/*.nupkg --api-key $NUGET_API_KEY --source "nuget.org" diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.gitignore b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.gitignore new file mode 100644 index 000000000000..11014f2b33d7 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/.gitignore @@ -0,0 +1,484 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +## This is based on `dotnet new gitignore` and customized by Fern + +# dotenv files +.env + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +# [Rr]elease/ (Ignored by Fern) +# [Rr]eleases/ (Ignored by Fern) +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +# [Ll]og/ (Ignored by Fern) +# [Ll]ogs/ (Ignored by Fern) + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/CONTRIBUTING.md b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/CONTRIBUTING.md new file mode 100644 index 000000000000..1de047696582 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/CONTRIBUTING.md @@ -0,0 +1,119 @@ +# Contributing + +Thanks for your interest in contributing to this SDK! This document provides guidelines for contributing to the project. + +## Getting Started + +### Prerequisites + +- .NET SDK (version compatible with the target frameworks: net462, net8.0, netstandard2.0) + +### Installation + +Install the project dependencies: + +```bash +dotnet restore +``` + +### Building + +Build the project: + +```bash +dotnet build +``` + +### Testing + +Run the test suite: + +```bash +dotnet test +``` + +### Formatting + +Check code style: + +```bash +dotnet format --verify-no-changes +``` + +Fix code style issues: + +```bash +dotnet format +``` + +## About Generated Code + +**Important**: Most files in this SDK are automatically generated by [Fern](https://buildwithfern.com) from the API definition. Direct modifications to generated files will be overwritten the next time the SDK is generated. + +### Generated Files + +The following directories contain generated code: +- `src/` - API client classes and types +- Most C# files in the project + +### How to Customize + +If you need to customize the SDK, you have two options: + +#### Option 1: Use `.fernignore` + +For custom code that should persist across SDK regenerations: + +1. Create a `.fernignore` file in the project root +2. Add file patterns for files you want to preserve (similar to `.gitignore` syntax) +3. Add your custom code to those files + +Files listed in `.fernignore` will not be overwritten when the SDK is regenerated. + +For more information, see the [Fern documentation on custom code](https://buildwithfern.com/learn/sdks/overview/custom-code). + +#### Option 2: Contribute to the Generator + +If you want to change how code is generated for all users of this SDK: + +1. The C# SDK generator lives in the [Fern repository](https://github.com/fern-api/fern) +2. Generator code is located at `generators/csharp/` +3. Follow the [Fern contributing guidelines](https://github.com/fern-api/fern/blob/main/CONTRIBUTING.md) +4. Submit a pull request with your changes to the generator + +This approach is best for: +- Bug fixes in generated code +- New features that would benefit all users +- Improvements to code generation patterns + +## Making Changes + +### Workflow + +1. Create a new branch for your changes +2. Make your modifications +3. Run tests to ensure nothing breaks: `dotnet test` +4. Run formatting: `dotnet format` +5. Build the project: `dotnet build` +6. Commit your changes with a clear commit message +7. Push your branch and create a pull request + +### Commit Messages + +Write clear, descriptive commit messages that explain what changed and why. + +### Code Style + +This project uses automated code formatting. Run `dotnet format` before committing to ensure your code meets the project's style guidelines. + +## Questions or Issues? + +If you have questions or run into issues: + +1. Check the [Fern documentation](https://buildwithfern.com) +2. Search existing [GitHub issues](https://github.com/fern-api/fern/issues) +3. Open a new issue if your question hasn't been addressed + +## License + +By contributing to this project, you agree that your contributions will be licensed under the same license as the project. diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/README.md b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/README.md new file mode 100644 index 000000000000..271b5329326b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/README.md @@ -0,0 +1,213 @@ +# Seed C# Library + +[![fern shield](https://img.shields.io/badge/%F0%9F%8C%BF-Built%20with%20Fern-brightgreen)](https://buildwithfern.com?utm_source=github&utm_medium=github&utm_campaign=readme&utm_source=Seed%2FC%23) +[![nuget shield](https://img.shields.io/nuget/v/Ferncsharp-xml-entities)](https://nuget.org/packages/Ferncsharp-xml-entities) + +The Seed C# library provides convenient access to the Seed APIs from C#. + +## Table of Contents + +- [Requirements](#requirements) +- [Installation](#installation) +- [Reference](#reference) +- [Usage](#usage) +- [Exception Handling](#exception-handling) +- [Advanced](#advanced) + - [Retries](#retries) + - [Timeouts](#timeouts) + - [Raw Response](#raw-response) + - [Additional Headers](#additional-headers) + - [Additional Query Parameters](#additional-query-parameters) + - [Additional Body Properties](#additional-body-properties) +- [Contributing](#contributing) + +## Requirements + +This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above + +## Installation + +```sh +dotnet add package Ferncsharp-xml-entities +``` + +## Reference + +A full reference for this library is available [here](./reference.md). + +## Usage + +Instantiate and use the client with the following: + +```csharp +using SeedCsharpXmlEntities; + +var client = new SeedCsharpXmlEntitiesClient(); +await client.GetTimeZoneAsync(); +``` + +## Exception Handling + +When the API returns a non-success status code (4xx or 5xx response), a subclass of the following error +will be thrown. + +```csharp +using SeedCsharpXmlEntities; + +try { + var response = await client.GetTimeZoneAsync(...); +} catch (SeedCsharpXmlEntitiesApiException e) { + System.Console.WriteLine(e.Body); + System.Console.WriteLine(e.StatusCode); + + // Access the raw HTTP response (status code, URL, headers) off the exception + var rawResponse = e.RawResponse; + if (rawResponse != null) + { + System.Console.WriteLine(rawResponse.Url); + if (rawResponse.Headers.TryGetValue("X-Request-Id", out var requestId)) + { + System.Console.WriteLine($"Request ID: {requestId}"); + } + } +} +``` + +## Advanced + +### Retries + +The SDK is instrumented with automatic retries with exponential backoff. A request will be retried as long +as the request is deemed retryable and the number of retry attempts has not grown larger than the configured +retry limit (default: 2). + +Which status codes are retried depends on the `retryStatusCodes` generator configuration: + +**`legacy`** (current default): retries on +- [408](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) (Timeout) +- [429](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) (Too Many Requests) +- [5XX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#server_error_responses) (All server errors, including 500) + +**`recommended`**: retries on +- [408](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) (Timeout) +- [429](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) (Too Many Requests) +- [502](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502) (Bad Gateway) +- [503](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503) (Service Unavailable) +- [504](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504) (Gateway Timeout) + +Use the `MaxRetries` request option to configure this behavior. + +```csharp +var response = await client.GetTimeZoneAsync( + ..., + new RequestOptions { + MaxRetries = 0 // Override MaxRetries at the request level + } +); +``` + +### Timeouts + +The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure this behavior. + +```csharp +var response = await client.GetTimeZoneAsync( + ..., + new RequestOptions { + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s + } +); +``` + +### Raw Response + +Access raw HTTP response data (status code, headers, URL) alongside parsed response data using the `.WithRawResponse()` method. + +```csharp +using SeedCsharpXmlEntities; + +// Access raw response data (status code, headers, etc.) alongside the parsed response +var result = await client.GetTimeZoneAsync(...).WithRawResponse(); + +// Access the parsed data +var data = result.Data; + +// Access raw response metadata +var statusCode = result.RawResponse.StatusCode; +var headers = result.RawResponse.Headers; +var url = result.RawResponse.Url; + +// Access specific headers (case-insensitive) +if (headers.TryGetValue("X-Request-Id", out var requestId)) +{ + System.Console.WriteLine($"Request ID: {requestId}"); +} + +// For the default behavior, simply await without .WithRawResponse() +var parsedData = await client.GetTimeZoneAsync(...); + +// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) +// and on endpoints with no response body (returns RawResponse only). +``` + +### Additional Headers + +If you would like to send additional headers as part of the request, use the `AdditionalHeaders` request option. + +```csharp +var response = await client.GetTimeZoneAsync( + ..., + new RequestOptions { + AdditionalHeaders = new Dictionary + { + { "X-Custom-Header", "custom-value" } + } + } +); +``` + +### Additional Query Parameters + +If you would like to send additional query parameters as part of the request, use the `AdditionalQueryParameters` request option. + +```csharp +var response = await client.GetTimeZoneAsync( + ..., + new RequestOptions { + AdditionalQueryParameters = new Dictionary + { + { "custom_param", "custom-value" } + } + } +); +``` + +### Additional Body Properties + +If you would like to send additional body properties as part of the request, use the `AdditionalBodyProperties` request option. +This is only applied to JSON requests. + +```csharp +var response = await client.GetTimeZoneAsync( + ..., + new RequestOptions { + AdditionalBodyProperties = new Dictionary + { + { "custom_field", "custom-value" } + } + } +); +``` + +## Contributing + +While we value open-source contributions to this SDK, this library is generated programmatically. +Additions made directly to this library would have to be moved over to our generation code, +otherwise they would be overwritten upon the next generated release. Feel free to open a PR as +a proof of concept, but know that we will not be able to merge it as-is. We suggest opening +an issue first to discuss with us! + +On the other hand, contributions to the README are always very welcome! diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/SeedCsharpXmlEntities.slnx b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/SeedCsharpXmlEntities.slnx new file mode 100644 index 000000000000..706a3f8d4cb4 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/SeedCsharpXmlEntities.slnx @@ -0,0 +1,4 @@ + + + + diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/Snippets/Example0.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/Snippets/Example0.cs new file mode 100644 index 000000000000..1db08fcd34b7 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/Snippets/Example0.cs @@ -0,0 +1,15 @@ +using SeedCsharpXmlEntities; + +public partial class Examples +{ + public async Task Example0() { + var client = new SeedCsharpXmlEntitiesClient( + clientOptions: new ClientOptions { + BaseUrl = "https://api.fern.com" + } + ); + + await client.GetTimeZoneAsync(); + } + +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/Snippets/Snippets.csproj b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/Snippets/Snippets.csproj new file mode 100644 index 000000000000..8d1c06d60829 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/Snippets/Snippets.csproj @@ -0,0 +1,11 @@ + + + net10.0 + Snippets + enable + enable + + + + + \ No newline at end of file diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/reference.md b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/reference.md new file mode 100644 index 000000000000..3a397642ffbc --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/reference.md @@ -0,0 +1,40 @@ +# Reference +
client.GetTimeZoneAsync() -> WithRawResponseTask<TimeZoneModel> +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get timezone information with + offset +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.GetTimeZoneAsync(); +``` +
+
+
+
+ + +
+
+
+ diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/snippet.json b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/snippet.json new file mode 100644 index 000000000000..0c0af050ab0f --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/snippet.json @@ -0,0 +1,17 @@ +{ + "types": {}, + "endpoints": [ + { + "example_identifier": null, + "id": { + "path": "/timezone", + "method": "GET", + "identifier_override": "endpoint_.getTimeZone" + }, + "snippet": { + "type": "csharp", + "client": "using SeedCsharpXmlEntities;\n\nvar client = new SeedCsharpXmlEntitiesClient();\nawait client.GetTimeZoneAsync();\n" + } + } + ] +} \ No newline at end of file diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/HeadersBuilderTests.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/HeadersBuilderTests.cs new file mode 100644 index 000000000000..d946b28d4ded --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/HeadersBuilderTests.cs @@ -0,0 +1,326 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core; + +[TestFixture] +public class HeadersBuilderTests +{ + [Test] + public async global::System.Threading.Tasks.Task Add_SimpleHeaders() + { + var headers = await new HeadersBuilder.Builder() + .Add("Content-Type", "application/json") + .Add("Authorization", "Bearer token123") + .Add("X-API-Key", "key456") + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(3)); + Assert.That(headers["Content-Type"], Is.EqualTo("application/json")); + Assert.That(headers["Authorization"], Is.EqualTo("Bearer token123")); + Assert.That(headers["X-API-Key"], Is.EqualTo("key456")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_NullValuesIgnored() + { + var headers = await new HeadersBuilder.Builder() + .Add("Header1", "value1") + .Add("Header2", null) + .Add("Header3", "value3") + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(2)); + Assert.That(headers.ContainsKey("Header1"), Is.True); + Assert.That(headers.ContainsKey("Header2"), Is.False); + Assert.That(headers.ContainsKey("Header3"), Is.True); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_OverwritesExistingHeader() + { + var headers = await new HeadersBuilder.Builder() + .Add("Content-Type", "application/json") + .Add("Content-Type", "application/xml") + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(1)); + Assert.That(headers["Content-Type"], Is.EqualTo("application/xml")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_HeadersOverload_MergesExistingHeaders() + { + var existingHeaders = new Headers( + new Dictionary { { "Header1", "value1" }, { "Header2", "value2" } } + ); + + var result = await new HeadersBuilder.Builder() + .Add("Header3", "value3") + .Add(existingHeaders) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(result.Count, Is.EqualTo(3)); + Assert.That(result["Header1"], Is.EqualTo("value1")); + Assert.That(result["Header2"], Is.EqualTo("value2")); + Assert.That(result["Header3"], Is.EqualTo("value3")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_HeadersOverload_OverwritesExistingHeaders() + { + var existingHeaders = new Headers( + new Dictionary { { "Header1", "override" } } + ); + + var result = await new HeadersBuilder.Builder() + .Add("Header1", "original") + .Add("Header2", "keep") + .Add(existingHeaders) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(result.Count, Is.EqualTo(2)); + Assert.That(result["Header1"], Is.EqualTo("override")); + Assert.That(result["Header2"], Is.EqualTo("keep")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_HeadersOverload_NullHeadersIgnored() + { + var result = await new HeadersBuilder.Builder() + .Add("Header1", "value1") + .Add((Headers?)null) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result["Header1"], Is.EqualTo("value1")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_KeyValuePairOverload_AddsHeaders() + { + var additionalHeaders = new List> + { + new("Header1", "value1"), + new("Header2", "value2"), + }; + + var headers = await new HeadersBuilder.Builder() + .Add("Header3", "value3") + .Add(additionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(3)); + Assert.That(headers["Header1"], Is.EqualTo("value1")); + Assert.That(headers["Header2"], Is.EqualTo("value2")); + Assert.That(headers["Header3"], Is.EqualTo("value3")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_KeyValuePairOverload_IgnoresNullValues() + { + var additionalHeaders = new List> + { + new("Header1", "value1"), + new("Header2", null), // Should be ignored + }; + + var headers = await new HeadersBuilder.Builder() + .Add(additionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(1)); + Assert.That(headers.ContainsKey("Header2"), Is.False); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_DictionaryOverload_AddsHeaders() + { + var dict = new Dictionary + { + { "Header1", "value1" }, + { "Header2", "value2" }, + }; + + var headers = await new HeadersBuilder.Builder() + .Add("Header3", "value3") + .Add(dict) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(3)); + Assert.That(headers["Header1"], Is.EqualTo("value1")); + Assert.That(headers["Header2"], Is.EqualTo("value2")); + Assert.That(headers["Header3"], Is.EqualTo("value3")); + } + + [Test] + public async global::System.Threading.Tasks.Task EmptyBuilder_ReturnsEmptyHeaders() + { + var headers = await new HeadersBuilder.Builder().BuildAsync().ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(0)); + } + + [Test] + public async global::System.Threading.Tasks.Task OnlyNullValues_ReturnsEmptyHeaders() + { + var headers = await new HeadersBuilder.Builder() + .Add("Header1", null) + .Add("Header2", null) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(0)); + } + + [Test] + public async global::System.Threading.Tasks.Task ComplexMergingScenario() + { + // Simulates real SDK usage: endpoint headers + client headers + request options + var clientHeaders = new Headers( + new Dictionary + { + { "X-Client-Version", "1.0.0" }, + { "User-Agent", "MyClient/1.0" }, + } + ); + + var clientAdditionalHeaders = new List> + { + new("X-Custom-Header", "custom-value"), + }; + + var requestOptionsHeaders = new Headers( + new Dictionary + { + { "Authorization", "Bearer user-token" }, + { "User-Agent", "MyClient/2.0" }, // Override + } + ); + + var requestAdditionalHeaders = new List> + { + new("X-Request-ID", "req-123"), + new("X-Custom-Header", "overridden-value"), // Override + }; + + var headers = await new HeadersBuilder.Builder() + .Add("Content-Type", "application/json") // Endpoint header + .Add("X-Endpoint-ID", "endpoint-1") + .Add(clientHeaders) + .Add(clientAdditionalHeaders) + .Add(requestOptionsHeaders) + .Add(requestAdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + + // Verify precedence + Assert.That(headers["Content-Type"], Is.EqualTo("application/json")); + Assert.That(headers["X-Endpoint-ID"], Is.EqualTo("endpoint-1")); + Assert.That(headers["X-Client-Version"], Is.EqualTo("1.0.0")); + Assert.That(headers["User-Agent"], Is.EqualTo("MyClient/2.0")); // Overridden + Assert.That(headers["Authorization"], Is.EqualTo("Bearer user-token")); + Assert.That(headers["X-Request-ID"], Is.EqualTo("req-123")); + Assert.That(headers["X-Custom-Header"], Is.EqualTo("overridden-value")); // Overridden + } + + [Test] + public async global::System.Threading.Tasks.Task Builder_WithCapacity() + { + // Test that capacity constructor works without errors + var headers = await new HeadersBuilder.Builder(capacity: 10) + .Add("Header1", "value1") + .Add("Header2", "value2") + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(2)); + Assert.That(headers["Header1"], Is.EqualTo("value1")); + Assert.That(headers["Header2"], Is.EqualTo("value2")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_HeadersOverload_ResolvesDynamicHeaderValues() + { + // Test that BuildAsync properly resolves HeaderValue instances + var existingHeaders = new Headers(); + existingHeaders["DynamicHeader"] = + (Func>)( + () => global::System.Threading.Tasks.Task.FromResult("dynamic-value") + ); + + var result = await new HeadersBuilder.Builder() + .Add("StaticHeader", "static-value") + .Add(existingHeaders) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(result.Count, Is.EqualTo(2)); + Assert.That(result["StaticHeader"], Is.EqualTo("static-value")); + Assert.That(result["DynamicHeader"], Is.EqualTo("dynamic-value")); + } + + [Test] + public async global::System.Threading.Tasks.Task MultipleSyncAdds() + { + var headers1 = new Headers(new Dictionary { { "H1", "v1" } }); + var headers2 = new Headers(new Dictionary { { "H2", "v2" } }); + var headers3 = new Headers(new Dictionary { { "H3", "v3" } }); + + var result = await new HeadersBuilder.Builder() + .Add(headers1) + .Add(headers2) + .Add(headers3) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(result.Count, Is.EqualTo(3)); + Assert.That(result["H1"], Is.EqualTo("v1")); + Assert.That(result["H2"], Is.EqualTo("v2")); + Assert.That(result["H3"], Is.EqualTo("v3")); + } + + [Test] + public async global::System.Threading.Tasks.Task PrecedenceOrder_LatestWins() + { + // Test that later operations override earlier ones + var headers1 = new Headers(new Dictionary { { "Key", "value1" } }); + var headers2 = new Headers(new Dictionary { { "Key", "value2" } }); + var additional = new List> { new("Key", "value3") }; + + var result = await new HeadersBuilder.Builder() + .Add("Key", "value0") + .Add(headers1) + .Add(headers2) + .Add(additional) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(result["Key"], Is.EqualTo("value3")); + } + + [Test] + public async global::System.Threading.Tasks.Task CaseInsensitiveKeys() + { + // Test that header keys are case-insensitive + var headers = await new HeadersBuilder.Builder() + .Add("content-type", "application/json") + .Add("Content-Type", "application/xml") // Should overwrite + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(1)); + Assert.That(headers["content-type"], Is.EqualTo("application/xml")); + Assert.That(headers["Content-Type"], Is.EqualTo("application/xml")); + Assert.That(headers["CONTENT-TYPE"], Is.EqualTo("application/xml")); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/AdditionalPropertiesTests.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/AdditionalPropertiesTests.cs new file mode 100644 index 000000000000..2cfb0e4a4b18 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/AdditionalPropertiesTests.cs @@ -0,0 +1,365 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core.Json; + +[TestFixture] +public class AdditionalPropertiesTests +{ + [Test] + public void Record_OnDeserialized_ShouldPopulateAdditionalProperties() + { + // Arrange + const string json = """ + { + "id": "1", + "category": "fiction", + "title": "The Hobbit" + } + """; + + // Act + var record = JsonUtils.Deserialize(json); + + // Assert + Assert.That(record, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(record.Id, Is.EqualTo("1")); + Assert.That(record.AdditionalProperties["category"].GetString(), Is.EqualTo("fiction")); + Assert.That(record.AdditionalProperties["title"].GetString(), Is.EqualTo("The Hobbit")); + }); + } + + [Test] + public void RecordWithWriteableAdditionalProperties_OnSerialization_ShouldIncludeAdditionalProperties() + { + // Arrange + var record = new WriteableRecord + { + Id = "1", + AdditionalProperties = { ["category"] = "fiction", ["title"] = "The Hobbit" }, + }; + + // Act + var json = JsonUtils.Serialize(record); + var deserializedRecord = JsonUtils.Deserialize(json); + + // Assert + Assert.That(deserializedRecord, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(deserializedRecord.Id, Is.EqualTo("1")); + Assert.That( + deserializedRecord.AdditionalProperties["category"], + Is.InstanceOf() + ); + Assert.That( + ((JsonElement)deserializedRecord.AdditionalProperties["category"]!).GetString(), + Is.EqualTo("fiction") + ); + Assert.That( + deserializedRecord.AdditionalProperties["title"], + Is.InstanceOf() + ); + Assert.That( + ((JsonElement)deserializedRecord.AdditionalProperties["title"]!).GetString(), + Is.EqualTo("The Hobbit") + ); + }); + } + + [Test] + public void ReadOnlyAdditionalProperties_ShouldRetrieveValuesCorrectly() + { + // Arrange + var extensionData = new Dictionary + { + ["key1"] = JsonUtils.SerializeToElement("value1"), + ["key2"] = JsonUtils.SerializeToElement(123), + }; + var readOnlyProps = new ReadOnlyAdditionalProperties(); + readOnlyProps.CopyFromExtensionData(extensionData); + + // Act & Assert + Assert.That(readOnlyProps["key1"].GetString(), Is.EqualTo("value1")); + Assert.That(readOnlyProps["key2"].GetInt32(), Is.EqualTo(123)); + } + + [Test] + public void AdditionalProperties_ShouldBehaveAsDictionary() + { + // Arrange + var additionalProps = new AdditionalProperties { ["key1"] = "value1", ["key2"] = 123 }; + + // Act + additionalProps["key3"] = true; + + // Assert + Assert.Multiple(() => + { + Assert.That(additionalProps["key1"], Is.EqualTo("value1")); + Assert.That(additionalProps["key2"], Is.EqualTo(123)); + Assert.That((bool)additionalProps["key3"]!, Is.True); + Assert.That(additionalProps.Count, Is.EqualTo(3)); + }); + } + + [Test] + public void AdditionalProperties_ToJsonObject_ShouldSerializeCorrectly() + { + // Arrange + var additionalProps = new AdditionalProperties { ["key1"] = "value1", ["key2"] = 123 }; + + // Act + var jsonObject = additionalProps.ToJsonObject(); + + Assert.Multiple(() => + { + // Assert + Assert.That(jsonObject["key1"]!.GetValue(), Is.EqualTo("value1")); + Assert.That(jsonObject["key2"]!.GetValue(), Is.EqualTo(123)); + }); + } + + [Test] + public void AdditionalProperties_MixReadAndWrite_ShouldOverwriteDeserializedProperty() + { + // Arrange + const string json = """ + { + "id": "1", + "category": "fiction", + "title": "The Hobbit" + } + """; + var record = JsonUtils.Deserialize(json); + + // Act + record.AdditionalProperties["category"] = "non-fiction"; + + // Assert + Assert.Multiple(() => + { + Assert.That(record, Is.Not.Null); + Assert.That(record.Id, Is.EqualTo("1")); + Assert.That(record.AdditionalProperties["category"], Is.EqualTo("non-fiction")); + Assert.That(record.AdditionalProperties["title"], Is.InstanceOf()); + Assert.That( + ((JsonElement)record.AdditionalProperties["title"]!).GetString(), + Is.EqualTo("The Hobbit") + ); + }); + } + + [Test] + public void RecordWithReadonlyAdditionalPropertiesInts_OnDeserialized_ShouldPopulateAdditionalProperties() + { + // Arrange + const string json = """ + { + "extra1": 42, + "extra2": 99 + } + """; + + // Act + var record = JsonUtils.Deserialize(json); + + // Assert + Assert.That(record, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(record.AdditionalProperties["extra1"], Is.EqualTo(42)); + Assert.That(record.AdditionalProperties["extra2"], Is.EqualTo(99)); + }); + } + + [Test] + public void RecordWithAdditionalPropertiesInts_OnSerialization_ShouldIncludeAdditionalProperties() + { + // Arrange + var record = new WriteableRecordWithInts + { + AdditionalProperties = { ["extra1"] = 42, ["extra2"] = 99 }, + }; + + // Act + var json = JsonUtils.Serialize(record); + var deserializedRecord = JsonUtils.Deserialize(json); + + // Assert + Assert.That(deserializedRecord, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(deserializedRecord.AdditionalProperties["extra1"], Is.EqualTo(42)); + Assert.That(deserializedRecord.AdditionalProperties["extra2"], Is.EqualTo(99)); + }); + } + + [Test] + public void RecordWithReadonlyAdditionalPropertiesDictionaries_OnDeserialized_ShouldPopulateAdditionalProperties() + { + // Arrange + const string json = """ + { + "extra1": { "key1": true, "key2": false }, + "extra2": { "key3": true } + } + """; + + // Act + var record = JsonUtils.Deserialize(json); + + // Assert + Assert.That(record, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(record.AdditionalProperties["extra1"]["key1"], Is.True); + Assert.That(record.AdditionalProperties["extra1"]["key2"], Is.False); + Assert.That(record.AdditionalProperties["extra2"]["key3"], Is.True); + }); + } + + [Test] + public void RecordWithAdditionalPropertiesDictionaries_OnSerialization_ShouldIncludeAdditionalProperties() + { + // Arrange + var record = new WriteableRecordWithDictionaries + { + AdditionalProperties = + { + ["extra1"] = new Dictionary { { "key1", true }, { "key2", false } }, + ["extra2"] = new Dictionary { { "key3", true } }, + }, + }; + + // Act + var json = JsonUtils.Serialize(record); + var deserializedRecord = JsonUtils.Deserialize(json); + + // Assert + Assert.That(deserializedRecord, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(deserializedRecord.AdditionalProperties["extra1"]["key1"], Is.True); + Assert.That(deserializedRecord.AdditionalProperties["extra1"]["key2"], Is.False); + Assert.That(deserializedRecord.AdditionalProperties["extra2"]["key3"], Is.True); + }); + } + + private record Record : IJsonOnDeserialized + { + [JsonPropertyName("id")] + public required string Id { get; set; } + + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; } = new(); + + void IJsonOnDeserialized.OnDeserialized() + { + AdditionalProperties.CopyFromExtensionData(_extensionData); + } + } + + private record WriteableRecord : IJsonOnDeserialized, IJsonOnSerializing + { + [JsonPropertyName("id")] + public required string Id { get; set; } + + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonIgnore] + public AdditionalProperties AdditionalProperties { get; set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() + { + AdditionalProperties.CopyFromExtensionData(_extensionData); + } + + void IJsonOnSerializing.OnSerializing() + { + AdditionalProperties.CopyToExtensionData(_extensionData); + } + } + + private record RecordWithInts : IJsonOnDeserialized + { + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; } = new(); + + void IJsonOnDeserialized.OnDeserialized() + { + AdditionalProperties.CopyFromExtensionData(_extensionData); + } + } + + private record WriteableRecordWithInts : IJsonOnDeserialized, IJsonOnSerializing + { + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonIgnore] + public AdditionalProperties AdditionalProperties { get; } = new(); + + void IJsonOnDeserialized.OnDeserialized() + { + AdditionalProperties.CopyFromExtensionData(_extensionData); + } + + void IJsonOnSerializing.OnSerializing() + { + AdditionalProperties.CopyToExtensionData(_extensionData); + } + } + + private record RecordWithDictionaries : IJsonOnDeserialized + { + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonIgnore] + public ReadOnlyAdditionalProperties< + Dictionary + > AdditionalProperties { get; } = new(); + + void IJsonOnDeserialized.OnDeserialized() + { + AdditionalProperties.CopyFromExtensionData(_extensionData); + } + } + + private record WriteableRecordWithDictionaries : IJsonOnDeserialized, IJsonOnSerializing + { + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonIgnore] + public AdditionalProperties> AdditionalProperties { get; } = new(); + + void IJsonOnDeserialized.OnDeserialized() + { + AdditionalProperties.CopyFromExtensionData(_extensionData); + } + + void IJsonOnSerializing.OnSerializing() + { + AdditionalProperties.CopyToExtensionData(_extensionData); + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/DateOnlyJsonTests.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/DateOnlyJsonTests.cs new file mode 100644 index 000000000000..af1ea78d56b9 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/DateOnlyJsonTests.cs @@ -0,0 +1,100 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core.Json; + +[TestFixture] +public class DateOnlyJsonTests +{ + [Test] + public void SerializeDateOnly_ShouldMatchExpectedFormat() + { + (DateOnly dateOnly, string expected)[] testCases = + [ + (new DateOnly(2023, 10, 5), "\"2023-10-05\""), + (new DateOnly(2023, 1, 1), "\"2023-01-01\""), + (new DateOnly(2023, 12, 31), "\"2023-12-31\""), + (new DateOnly(2023, 6, 15), "\"2023-06-15\""), + (new DateOnly(2023, 3, 10), "\"2023-03-10\""), + ]; + foreach (var (dateOnly, expected) in testCases) + { + var json = JsonUtils.Serialize(dateOnly); + Assert.That(json, Is.EqualTo(expected)); + } + } + + [Test] + public void DeserializeDateOnly_ShouldMatchExpectedDateOnly() + { + (DateOnly expected, string json)[] testCases = + [ + (new DateOnly(2023, 10, 5), "\"2023-10-05\""), + (new DateOnly(2023, 1, 1), "\"2023-01-01\""), + (new DateOnly(2023, 12, 31), "\"2023-12-31\""), + (new DateOnly(2023, 6, 15), "\"2023-06-15\""), + (new DateOnly(2023, 3, 10), "\"2023-03-10\""), + ]; + + foreach (var (expected, json) in testCases) + { + var dateOnly = JsonUtils.Deserialize(json); + Assert.That(dateOnly, Is.EqualTo(expected)); + } + } + + [Test] + public void SerializeNullableDateOnly_ShouldMatchExpectedFormat() + { + (DateOnly? dateOnly, string expected)[] testCases = + [ + (new DateOnly(2023, 10, 5), "\"2023-10-05\""), + (null, "null"), + ]; + foreach (var (dateOnly, expected) in testCases) + { + var json = JsonUtils.Serialize(dateOnly); + Assert.That(json, Is.EqualTo(expected)); + } + } + + [Test] + public void DeserializeNullableDateOnly_ShouldMatchExpectedDateOnly() + { + (DateOnly? expected, string json)[] testCases = + [ + (new DateOnly(2023, 10, 5), "\"2023-10-05\""), + (null, "null"), + ]; + + foreach (var (expected, json) in testCases) + { + var dateOnly = JsonUtils.Deserialize(json); + Assert.That(dateOnly, Is.EqualTo(expected)); + } + } + + [Test] + public void ShouldSerializeDictionaryWithDateOnlyKey() + { + var key = new DateOnly(2023, 10, 5); + var dict = new Dictionary { { key, "value_a" } }; + var json = JsonUtils.Serialize(dict); + Assert.That(json, Does.Contain("2023-10-05")); + Assert.That(json, Does.Contain("value_a")); + } + + [Test] + public void ShouldDeserializeDictionaryWithDateOnlyKey() + { + var json = """ + { + "2023-10-05": "value_a" + } + """; + var dict = JsonUtils.Deserialize>(json); + Assert.That(dict, Is.Not.Null); + var key = new DateOnly(2023, 10, 5); + Assert.That(dict![key], Is.EqualTo("value_a")); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/DateTimeJsonTests.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/DateTimeJsonTests.cs new file mode 100644 index 000000000000..5d878a684a26 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/DateTimeJsonTests.cs @@ -0,0 +1,134 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core.Json; + +[TestFixture] +public class DateTimeJsonTests +{ + [Test] + public void SerializeDateTime_ShouldMatchExpectedFormat() + { + (DateTime dateTime, string expected)[] testCases = + [ + ( + new DateTime(2023, 10, 5, 14, 30, 0, DateTimeKind.Utc), + "\"2023-10-05T14:30:00.000Z\"" + ), + (new DateTime(2023, 1, 1, 0, 0, 0, DateTimeKind.Utc), "\"2023-01-01T00:00:00.000Z\""), + ( + new DateTime(2023, 12, 31, 23, 59, 59, DateTimeKind.Utc), + "\"2023-12-31T23:59:59.000Z\"" + ), + (new DateTime(2023, 6, 15, 12, 0, 0, DateTimeKind.Utc), "\"2023-06-15T12:00:00.000Z\""), + ( + new DateTime(2023, 3, 10, 8, 45, 30, DateTimeKind.Utc), + "\"2023-03-10T08:45:30.000Z\"" + ), + ( + new DateTime(2023, 3, 10, 8, 45, 30, 123, DateTimeKind.Utc), + "\"2023-03-10T08:45:30.123Z\"" + ), + ]; + foreach (var (dateTime, expected) in testCases) + { + var json = JsonUtils.Serialize(dateTime); + Assert.That(json, Is.EqualTo(expected)); + } + } + + [Test] + public void DeserializeDateTime_ShouldMatchExpectedDateTime() + { + (DateTime expected, string json)[] testCases = + [ + ( + new DateTime(2023, 10, 5, 14, 30, 0, DateTimeKind.Utc), + "\"2023-10-05T14:30:00.000Z\"" + ), + (new DateTime(2023, 1, 1, 0, 0, 0, DateTimeKind.Utc), "\"2023-01-01T00:00:00.000Z\""), + ( + new DateTime(2023, 12, 31, 23, 59, 59, DateTimeKind.Utc), + "\"2023-12-31T23:59:59.000Z\"" + ), + (new DateTime(2023, 6, 15, 12, 0, 0, DateTimeKind.Utc), "\"2023-06-15T12:00:00.000Z\""), + ( + new DateTime(2023, 3, 10, 8, 45, 30, DateTimeKind.Utc), + "\"2023-03-10T08:45:30.000Z\"" + ), + (new DateTime(2023, 3, 10, 8, 45, 30, DateTimeKind.Utc), "\"2023-03-10T08:45:30Z\""), + ( + new DateTime(2023, 3, 10, 8, 45, 30, 123, DateTimeKind.Utc), + "\"2023-03-10T08:45:30.123Z\"" + ), + ]; + + foreach (var (expected, json) in testCases) + { + var dateTime = JsonUtils.Deserialize(json); + Assert.That(dateTime, Is.EqualTo(expected)); + } + } + + [Test] + public void SerializeNullableDateTime_ShouldMatchExpectedFormat() + { + (DateTime? expected, string json)[] testCases = + [ + ( + new DateTime(2023, 10, 5, 14, 30, 0, DateTimeKind.Utc), + "\"2023-10-05T14:30:00.000Z\"" + ), + (null, "null"), + ]; + + foreach (var (expected, json) in testCases) + { + var dateTime = JsonUtils.Deserialize(json); + Assert.That(dateTime, Is.EqualTo(expected)); + } + } + + [Test] + public void DeserializeNullableDateTime_ShouldMatchExpectedDateTime() + { + (DateTime? expected, string json)[] testCases = + [ + ( + new DateTime(2023, 10, 5, 14, 30, 0, DateTimeKind.Utc), + "\"2023-10-05T14:30:00.000Z\"" + ), + (null, "null"), + ]; + + foreach (var (expected, json) in testCases) + { + var dateTime = JsonUtils.Deserialize(json); + Assert.That(dateTime, Is.EqualTo(expected)); + } + } + + [Test] + public void ShouldSerializeDictionaryWithDateTimeKey() + { + var key = new DateTime(2023, 10, 5, 14, 30, 0, DateTimeKind.Utc); + var dict = new Dictionary { { key, "value_a" } }; + var json = JsonUtils.Serialize(dict); + Assert.That(json, Does.Contain("2023-10-05T14:30:00.000Z")); + Assert.That(json, Does.Contain("value_a")); + } + + [Test] + public void ShouldDeserializeDictionaryWithDateTimeKey() + { + var json = """ + { + "2023-10-05T14:30:00.000Z": "value_a" + } + """; + var dict = JsonUtils.Deserialize>(json); + Assert.That(dict, Is.Not.Null); + var key = new DateTime(2023, 10, 5, 14, 30, 0, DateTimeKind.Utc); + Assert.That(dict![key], Is.EqualTo("value_a")); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/JsonAccessAttributeTests.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/JsonAccessAttributeTests.cs new file mode 100644 index 000000000000..8ec2b9b8ae13 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/Json/JsonAccessAttributeTests.cs @@ -0,0 +1,160 @@ +using global::System.Text.Json.Serialization; +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core.Json; + +[TestFixture] +public class JsonAccessAttributeTests +{ + private class MyClass + { + [JsonPropertyName("read_only_prop")] + [JsonAccess(JsonAccessType.ReadOnly)] + public string? ReadOnlyProp { get; set; } + + [JsonPropertyName("write_only_prop")] + [JsonAccess(JsonAccessType.WriteOnly)] + public string? WriteOnlyProp { get; set; } + + [JsonPropertyName("normal_prop")] + public string? NormalProp { get; set; } + + [JsonPropertyName("read_only_nullable_list")] + [JsonAccess(JsonAccessType.ReadOnly)] + public IEnumerable? ReadOnlyNullableList { get; set; } + + [JsonPropertyName("read_only_list")] + [JsonAccess(JsonAccessType.ReadOnly)] + public IEnumerable ReadOnlyList { get; set; } = []; + + [JsonPropertyName("write_only_nullable_list")] + [JsonAccess(JsonAccessType.WriteOnly)] + public IEnumerable? WriteOnlyNullableList { get; set; } + + [JsonPropertyName("write_only_list")] + [JsonAccess(JsonAccessType.WriteOnly)] + public IEnumerable WriteOnlyList { get; set; } = []; + + [JsonPropertyName("normal_list")] + public IEnumerable NormalList { get; set; } = []; + + [JsonPropertyName("normal_nullable_list")] + public IEnumerable? NullableNormalList { get; set; } + } + + [Test] + public void JsonAccessAttribute_ShouldWorkAsExpected() + { + const string json = """ + { + "read_only_prop": "read", + "write_only_prop": "write", + "normal_prop": "normal_prop", + "read_only_nullable_list": ["item1", "item2"], + "read_only_list": ["item3", "item4"], + "write_only_nullable_list": ["item5", "item6"], + "write_only_list": ["item7", "item8"], + "normal_list": ["normal1", "normal2"], + "normal_nullable_list": ["normal1", "normal2"] + } + """; + var obj = JsonUtils.Deserialize(json); + + Assert.Multiple(() => + { + // String properties + Assert.That(obj.ReadOnlyProp, Is.EqualTo("read")); + Assert.That(obj.WriteOnlyProp, Is.Null); + Assert.That(obj.NormalProp, Is.EqualTo("normal_prop")); + + // List properties - read only + var nullableReadOnlyList = obj.ReadOnlyNullableList?.ToArray(); + Assert.That(nullableReadOnlyList, Is.Not.Null); + Assert.That(nullableReadOnlyList, Has.Length.EqualTo(2)); + Assert.That(nullableReadOnlyList![0], Is.EqualTo("item1")); + Assert.That(nullableReadOnlyList![1], Is.EqualTo("item2")); + + var readOnlyList = obj.ReadOnlyList.ToArray(); + Assert.That(readOnlyList, Is.Not.Null); + Assert.That(readOnlyList, Has.Length.EqualTo(2)); + Assert.That(readOnlyList[0], Is.EqualTo("item3")); + Assert.That(readOnlyList[1], Is.EqualTo("item4")); + + // List properties - write only + Assert.That(obj.WriteOnlyNullableList, Is.Null); + Assert.That(obj.WriteOnlyList, Is.Not.Null); + Assert.That(obj.WriteOnlyList, Is.Empty); + + // Normal list property + var normalList = obj.NormalList.ToArray(); + Assert.That(normalList, Is.Not.Null); + Assert.That(normalList, Has.Length.EqualTo(2)); + Assert.That(normalList[0], Is.EqualTo("normal1")); + Assert.That(normalList[1], Is.EqualTo("normal2")); + }); + + // Set up values for serialization + obj.WriteOnlyProp = "write"; + obj.NormalProp = "new_value"; + obj.WriteOnlyNullableList = new List { "write1", "write2" }; + obj.WriteOnlyList = new List { "write3", "write4" }; + obj.NormalList = new List { "new_normal" }; + obj.NullableNormalList = new List { "new_normal" }; + + var serializedJson = JsonUtils.Serialize(obj); + const string expectedJson = """ + { + "write_only_prop": "write", + "normal_prop": "new_value", + "write_only_nullable_list": [ + "write1", + "write2" + ], + "write_only_list": [ + "write3", + "write4" + ], + "normal_list": [ + "new_normal" + ], + "normal_nullable_list": [ + "new_normal" + ] + } + """; + Assert.That(serializedJson, Is.EqualTo(expectedJson).IgnoreWhiteSpace); + } + + [Test] + public void JsonAccessAttribute_WithNullListsInJson_ShouldWorkAsExpected() + { + const string json = """ + { + "read_only_prop": "read", + "normal_prop": "normal_prop", + "read_only_nullable_list": null, + "read_only_list": [] + } + """; + var obj = JsonUtils.Deserialize(json); + + Assert.Multiple(() => + { + // Read-only nullable list should be null when JSON contains null + var nullableReadOnlyList = obj.ReadOnlyNullableList?.ToArray(); + Assert.That(nullableReadOnlyList, Is.Null); + + // Read-only non-nullable list should never be null, but empty when JSON contains null + var readOnlyList = obj.ReadOnlyList.ToArray(); // This should be initialized to an empty list by default + Assert.That(readOnlyList, Is.Not.Null); + Assert.That(readOnlyList, Is.Empty); + }); + + // Serialize and verify read-only lists are not included + var serializedJson = JsonUtils.Serialize(obj); + Assert.That(serializedJson, Does.Not.Contain("read_only_prop")); + Assert.That(serializedJson, Does.Not.Contain("read_only_nullable_list")); + Assert.That(serializedJson, Does.Not.Contain("read_only_list")); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/QueryStringBuilderTests.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/QueryStringBuilderTests.cs new file mode 100644 index 000000000000..ce6e70558eea --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/QueryStringBuilderTests.cs @@ -0,0 +1,672 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core; + +[TestFixture] +public class QueryStringBuilderTests +{ + [Test] + public void Build_SimpleParameters() + { + var parameters = new List> + { + new("name", "John Doe"), + new("age", "30"), + new("city", "New York"), + }; + + var result = QueryStringBuilder.Build(parameters); + + Assert.That(result, Is.EqualTo("?name=John%20Doe&age=30&city=New%20York")); + } + + [Test] + public void Build_EmptyList_ReturnsEmptyString() + { + var parameters = new List>(); + + var result = QueryStringBuilder.Build(parameters); + + Assert.That(result, Is.EqualTo(string.Empty)); + } + + [Test] + public void Build_SpecialCharacters() + { + var parameters = new List> + { + new("email", "test@example.com"), + new("url", "https://example.com/path?query=value"), + new("special", "a+b=c&d"), + }; + + var result = QueryStringBuilder.Build(parameters); + + Assert.That( + result, + Is.EqualTo( + "?email=test@example.com&url=https://example.com/path?query=value&special=a%2Bb=c%26d" + ) + ); + } + + [Test] + public void Build_UnicodeCharacters() + { + var parameters = new List> { new("greeting", "Hello 世界") }; + + var result = QueryStringBuilder.Build(parameters); + + // Verify the Chinese characters are properly UTF-8 encoded + Assert.That(result, Does.StartWith("?greeting=Hello%20")); + Assert.That(result, Does.Contain("%E4%B8%96%E7%95%8C")); // 世界 + } + + [Test] + public void Build_SessionSettings_DeepObject() + { + // Simulate session settings with nested properties + var sessionSettings = new + { + custom_session_id = "my-custom-session-id", + system_prompt = "You are a helpful assistant", + variables = new Dictionary + { + { "userName", "John" }, + { "userAge", 30 }, + { "isPremium", true }, + }, + }; + + // Build query parameters list + var queryParams = new List> { new("api_key", "test_key_123") }; + + // Add session_settings with prefix using the new overload + queryParams.AddRange( + QueryStringConverter.ToDeepObject("session_settings", sessionSettings) + ); + + var result = QueryStringBuilder.Build(queryParams); + + // Verify the result contains properly formatted deep object notation + // Note: Square brackets are URL-encoded as %5B and %5D + Assert.That(result, Does.StartWith("?api_key=test_key_123")); + Assert.That( + result, + Does.Contain("session_settings%5Bcustom_session_id%5D=my-custom-session-id") + ); + Assert.That( + result, + Does.Contain("session_settings%5Bsystem_prompt%5D=You%20are%20a%20helpful%20assistant") + ); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5BuserName%5D=John")); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5BuserAge%5D=30")); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5BisPremium%5D=true")); + + // Verify it's NOT JSON encoded (no braces or quotes in the original format) + Assert.That(result, Does.Not.Contain("%7B%22")); // Not {" sequence + } + + [Test] + public void Build_ChatApiLikeParameters() + { + // Simulate what ChatApi constructor does + var sessionSettings = new + { + system_prompt = "You are helpful", + variables = new Dictionary { { "name", "Alice" } }, + }; + + var queryParams = new List>(); + + // Simple parameters + var simpleParams = new Dictionary + { + { "access_token", "token123" }, + { "config_id", "config456" }, + { "api_key", "key789" }, + }; + queryParams.AddRange(QueryStringConverter.ToExplodedForm(simpleParams)); + + // Session settings as deep object with prefix + queryParams.AddRange( + QueryStringConverter.ToDeepObject("session_settings", sessionSettings) + ); + + var result = QueryStringBuilder.Build(queryParams); + + // Verify structure (square brackets are URL-encoded) + Assert.That(result, Does.StartWith("?")); + Assert.That(result, Does.Contain("access_token=token123")); + Assert.That(result, Does.Contain("config_id=config456")); + Assert.That(result, Does.Contain("api_key=key789")); + Assert.That( + result, + Does.Contain("session_settings%5Bsystem_prompt%5D=You%20are%20helpful") + ); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5Bname%5D=Alice")); + } + + [Test] + public void Build_ReservedCharacters_NotEncoded() + { + var parameters = new List> + { + new("path", "some-path"), + new("id", "123-456_789.test~value"), + }; + + var result = QueryStringBuilder.Build(parameters); + + // Safe query characters include RFC 3986 unreserved + sub-delimiters (except & = +) + : @ / + Assert.That(result, Is.EqualTo("?path=some-path&id=123-456_789.test~value")); + } + + [Test] + public void Builder_Add_SimpleParameters() + { + var result = new QueryStringBuilder.Builder() + .Add("name", "John Doe") + .Add("age", 30) + .Add("active", true) + .Build(); + + Assert.That(result, Does.Contain("name=John%20Doe")); + Assert.That(result, Does.Contain("age=30")); + Assert.That(result, Does.Contain("active=true")); + } + + [Test] + public void Builder_Add_NullValuesIgnored() + { + var result = new QueryStringBuilder.Builder() + .Add("name", "John") + .Add("middle", null) + .Add("age", 30) + .Build(); + + Assert.That(result, Does.Contain("name=John")); + Assert.That(result, Does.Contain("age=30")); + Assert.That(result, Does.Not.Contain("middle")); + } + + [Test] + public void Builder_AddDeepObject_WithPrefix() + { + var settings = new + { + custom_session_id = "id-123", + system_prompt = "You are helpful", + variables = new { name = "Alice", age = 25 }, + }; + + var result = new QueryStringBuilder.Builder() + .Add("api_key", "key123") + .AddDeepObject("session_settings", settings) + .Build(); + + Assert.That(result, Does.Contain("api_key=key123")); + Assert.That(result, Does.Contain("session_settings%5Bcustom_session_id%5D=id-123")); + Assert.That( + result, + Does.Contain("session_settings%5Bsystem_prompt%5D=You%20are%20helpful") + ); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5Bname%5D=Alice")); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5Bage%5D=25")); + } + + [Test] + public void Builder_AddDeepObject_NullIgnored() + { + var result = new QueryStringBuilder.Builder() + .Add("api_key", "key123") + .AddDeepObject("settings", null) + .Build(); + + Assert.That(result, Is.EqualTo("?api_key=key123")); + Assert.That(result, Does.Not.Contain("settings")); + } + + [Test] + public void Builder_AddExploded_WithPrefix() + { + var filter = new { status = "active", type = "user" }; + + var result = new QueryStringBuilder.Builder() + .Add("api_key", "key123") + .AddExploded("filter", filter) + .Build(); + + Assert.That(result, Does.Contain("api_key=key123")); + Assert.That(result, Does.Contain("filter%5Bstatus%5D=active")); + Assert.That(result, Does.Contain("filter%5Btype%5D=user")); + } + + [Test] + public void Builder_AddExploded_NullIgnored() + { + var result = new QueryStringBuilder.Builder() + .Add("api_key", "key123") + .AddExploded("filter", null) + .Build(); + + Assert.That(result, Is.EqualTo("?api_key=key123")); + Assert.That(result, Does.Not.Contain("filter")); + } + + [Test] + public void Builder_WithCapacity() + { + // Test that capacity constructor works without errors + var result = new QueryStringBuilder.Builder(capacity: 10) + .Add("param1", "value1") + .Add("param2", "value2") + .Build(); + + Assert.That(result, Does.Contain("param1=value1")); + Assert.That(result, Does.Contain("param2=value2")); + } + + [Test] + public void Builder_ChatApiLikeUsage() + { + // Simulate real usage from ChatApi + var sessionSettings = new + { + custom_session_id = "session-123", + variables = new Dictionary + { + { "userName", "John" }, + { "userAge", 30 }, + }, + }; + + var result = new QueryStringBuilder.Builder(capacity: 16) + .Add("access_token", "token123") + .Add("allow_connection", true) + .Add("config_id", "config456") + .Add("api_key", "key789") + .AddDeepObject("session_settings", sessionSettings) + .Build(); + + Assert.That(result, Does.StartWith("?")); + Assert.That(result, Does.Contain("access_token=token123")); + Assert.That(result, Does.Contain("allow_connection=true")); + Assert.That(result, Does.Contain("config_id=config456")); + Assert.That(result, Does.Contain("api_key=key789")); + Assert.That(result, Does.Contain("session_settings%5Bcustom_session_id%5D=session-123")); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5BuserName%5D=John")); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5BuserAge%5D=30")); + } + + [Test] + public void Builder_EmptyBuilder_ReturnsEmptyString() + { + var result = new QueryStringBuilder.Builder().Build(); + + Assert.That(result, Is.EqualTo(string.Empty)); + } + + [Test] + public void Builder_OnlyNullValues_ReturnsEmptyString() + { + var result = new QueryStringBuilder.Builder() + .Add("param1", null) + .Add("param2", null) + .AddDeepObject("settings", null) + .Build(); + + Assert.That(result, Is.EqualTo(string.Empty)); + } + + [Test] + public void Builder_Set_OverridesSingleValue() + { + var result = new QueryStringBuilder.Builder() + .Add("foo", "original") + .Set("foo", "override") + .Build(); + + Assert.That(result, Is.EqualTo("?foo=override")); + } + + [Test] + public void Builder_Set_OverridesMultipleValues() + { + var result = new QueryStringBuilder.Builder() + .Add("foo", "value1") + .Add("foo", "value2") + .Set("foo", "override") + .Build(); + + Assert.That(result, Is.EqualTo("?foo=override")); + } + + [Test] + public void Builder_Set_WithArray_CreatesMultipleParameters() + { + var result = new QueryStringBuilder.Builder() + .Add("foo", "original") + .Set("foo", new[] { "value1", "value2" }) + .Build(); + + Assert.That(result, Is.EqualTo("?foo=value1&foo=value2")); + } + + [Test] + public void Builder_Set_WithNull_RemovesParameter() + { + var result = new QueryStringBuilder.Builder() + .Add("foo", "original") + .Add("bar", "keep") + .Set("foo", null) + .Build(); + + Assert.That(result, Is.EqualTo("?bar=keep")); + } + + [Test] + public void Builder_MergeAdditional_WithSingleValues() + { + var additional = new List> + { + new("foo", "bar"), + new("baz", "qux"), + }; + + var result = new QueryStringBuilder.Builder() + .Add("existing", "value") + .MergeAdditional(additional) + .Build(); + + Assert.That(result, Does.Contain("existing=value")); + Assert.That(result, Does.Contain("foo=bar")); + Assert.That(result, Does.Contain("baz=qux")); + } + + [Test] + public void Builder_MergeAdditional_WithDuplicateKeys_CreatesList() + { + var additional = new List> + { + new("foo", "bar1"), + new("foo", "bar2"), + new("baz", "qux"), + }; + + var result = new QueryStringBuilder.Builder() + .Add("existing", "value") + .MergeAdditional(additional) + .Build(); + + Assert.That(result, Does.Contain("existing=value")); + Assert.That(result, Does.Contain("foo=bar1")); + Assert.That(result, Does.Contain("foo=bar2")); + Assert.That(result, Does.Contain("baz=qux")); + } + + [Test] + public void Builder_MergeAdditional_OverridesExistingParameters() + { + var additional = new List> { new("foo", "override") }; + + var result = new QueryStringBuilder.Builder() + .Add("foo", "original1") + .Add("foo", "original2") + .Add("bar", "keep") + .MergeAdditional(additional) + .Build(); + + Assert.That(result, Does.Contain("bar=keep")); + Assert.That(result, Does.Contain("foo=override")); + Assert.That(result, Does.Not.Contain("original1")); + Assert.That(result, Does.Not.Contain("original2")); + } + + [Test] + public void Builder_MergeAdditional_WithDuplicates_OverridesExisting() + { + var additional = new List> + { + new("foo", "new1"), + new("foo", "new2"), + new("foo", "new3"), + }; + + var result = new QueryStringBuilder.Builder() + .Add("foo", "original1") + .Add("foo", "original2") + .Add("bar", "keep") + .MergeAdditional(additional) + .Build(); + + Assert.That(result, Does.Contain("bar=keep")); + Assert.That(result, Does.Contain("foo=new1")); + Assert.That(result, Does.Contain("foo=new2")); + Assert.That(result, Does.Contain("foo=new3")); + Assert.That(result, Does.Not.Contain("original1")); + Assert.That(result, Does.Not.Contain("original2")); + } + + [Test] + public void Builder_MergeAdditional_WithNull_NoOp() + { + var result = new QueryStringBuilder.Builder() + .Add("foo", "value") + .MergeAdditional(null) + .Build(); + + Assert.That(result, Is.EqualTo("?foo=value")); + } + + [Test] + public void Builder_MergeAdditional_WithEmptyList_NoOp() + { + var additional = new List>(); + + var result = new QueryStringBuilder.Builder() + .Add("foo", "value") + .MergeAdditional(additional) + .Build(); + + Assert.That(result, Is.EqualTo("?foo=value")); + } + + [Test] + public void Builder_MergeAdditional_RealWorldScenario() + { + // SDK generates foo=foo1&foo=foo2 + var builder = new QueryStringBuilder.Builder() + .Add("foo", "foo1") + .Add("foo", "foo2") + .Add("bar", "baz"); + + // User provides foo=override in AdditionalQueryParameters + var additional = new List> { new("foo", "override") }; + + var result = builder.MergeAdditional(additional).Build(); + + // Result should be foo=override&bar=baz (user overrides SDK) + Assert.That(result, Does.Contain("bar=baz")); + Assert.That(result, Does.Contain("foo=override")); + Assert.That(result, Does.Not.Contain("foo1")); + Assert.That(result, Does.Not.Contain("foo2")); + } + + [Test] + public void Builder_MergeAdditional_UserProvidesMultipleValues() + { + // SDK generates no foo parameter + var builder = new QueryStringBuilder.Builder().Add("bar", "baz"); + + // User provides foo=bar1&foo=bar2 in AdditionalQueryParameters + var additional = new List> + { + new("foo", "bar1"), + new("foo", "bar2"), + }; + + var result = builder.MergeAdditional(additional).Build(); + + // Result should be bar=baz&foo=bar1&foo=bar2 + Assert.That(result, Does.Contain("bar=baz")); + Assert.That(result, Does.Contain("foo=bar1")); + Assert.That(result, Does.Contain("foo=bar2")); + } + + [Test] + public void Builder_Add_WithCollection_CreatesMultipleParameters() + { + var tags = new[] { "tag1", "tag2", "tag3" }; + var result = new QueryStringBuilder.Builder().Add("tag", tags).Build(); + + Assert.That(result, Does.Contain("tag=tag1")); + Assert.That(result, Does.Contain("tag=tag2")); + Assert.That(result, Does.Contain("tag=tag3")); + } + + [Test] + public void Builder_Add_WithList_CreatesMultipleParameters() + { + var ids = new List { 1, 2, 3 }; + var result = new QueryStringBuilder.Builder().Add("id", ids).Build(); + + Assert.That(result, Does.Contain("id=1")); + Assert.That(result, Does.Contain("id=2")); + Assert.That(result, Does.Contain("id=3")); + } + + [Test] + public void Builder_Set_WithCollection_ReplacesAllPreviousValues() + { + var result = new QueryStringBuilder.Builder() + .Add("id", 1) + .Add("id", 2) + .Set("id", new[] { 10, 20, 30 }) + .Build(); + + Assert.That(result, Does.Contain("id=10")); + Assert.That(result, Does.Contain("id=20")); + Assert.That(result, Does.Contain("id=30")); + // Check that old values are not present (use word boundaries to avoid false positives with id=10) + Assert.That(result, Does.Not.Contain("id=1&")); + Assert.That(result, Does.Not.Contain("id=2&")); + Assert.That(result, Does.Not.Contain("id=1?")); + Assert.That(result, Does.Not.Contain("id=2?")); + Assert.That(result, Does.Not.EndWith("id=1")); + Assert.That(result, Does.Not.EndWith("id=2")); + } + + [Test] + public void EncodePathSegment_UnreservedChars_NotEncoded() + { + var result = QueryStringBuilder.EncodePathSegment("hello-world_test.value~123"); + Assert.That(result, Is.EqualTo("hello-world_test.value~123")); + } + + [Test] + public void EncodePathSegment_SubDelimiters_NotEncoded() + { + // All sub-delimiters are safe in path segments per RFC 3986 + var result = QueryStringBuilder.EncodePathSegment("a!b$c&d'e(f)g*h+i,j;k=l"); + Assert.That(result, Is.EqualTo("a!b$c&d'e(f)g*h+i,j;k=l")); + } + + [Test] + public void EncodePathSegment_ColonAndAt_NotEncoded() + { + var result = QueryStringBuilder.EncodePathSegment("user@host:8080"); + Assert.That(result, Is.EqualTo("user@host:8080")); + } + + [Test] + public void EncodePathSegment_SlashAndQuestion_Encoded() + { + // "/" and "?" are NOT part of pchar, so they must be encoded in path segments + var result = QueryStringBuilder.EncodePathSegment("path/with?query"); + Assert.That(result, Is.EqualTo("path%2Fwith%3Fquery")); + } + + [Test] + public void EncodePathSegment_Space_Encoded() + { + var result = QueryStringBuilder.EncodePathSegment("hello world"); + Assert.That(result, Is.EqualTo("hello%20world")); + } + + [Test] + public void EncodePathSegment_EmptyAndNull() + { + Assert.That(QueryStringBuilder.EncodePathSegment(""), Is.EqualTo("")); + Assert.That(QueryStringBuilder.EncodePathSegment(null!), Is.Null); + } + + [Test] + public void Build_QueryKeyVsValue_DifferentEncoding() + { + // "=" is safe in query values but NOT in query keys + var parameters = new List> + { + new("key=with=equals", "value=with=equals"), + }; + + var result = QueryStringBuilder.Build(parameters); + + // Key: "=" must be encoded + // Value: "=" is safe (part of query value safe chars) + Assert.That(result, Is.EqualTo("?key%3Dwith%3Dequals=value=with=equals")); + } + + [Test] + public void Build_QueryValue_QuestionMarkNotEncoded() + { + // "?" is safe in both query keys and query values per RFC 3986 + var parameters = new List> { new("q?key", "is this?") }; + + var result = QueryStringBuilder.Build(parameters); + + Assert.That(result, Is.EqualTo("?q?key=is%20this?")); + } + + [Test] + public void Build_QueryKey_PlusEncoded() + { + // "+" must be encoded in both query keys and query values + var parameters = new List> { new("a+b", "c+d") }; + + var result = QueryStringBuilder.Build(parameters); + + Assert.That(result, Is.EqualTo("?a%2Bb=c%2Bd")); + } + + [Test] + public void Build_Semicolon_Encoded() + { + // ";" is a legacy parameter separator, so it must be encoded in keys and values + var parameters = new List> + { + new("a;b", "jo@example.com; ceo@example.com"), + }; + + var result = QueryStringBuilder.Build(parameters); + + Assert.That(result, Is.EqualTo("?a%3Bb=jo@example.com%3B%20ceo@example.com")); + } + + [Test] + public void Build_ODataFilter_DollarPreserved() + { + // "$" is safe in query keys (sub-delimiter), verifies OData-style parameters work + var parameters = new List> + { + new("$filter", "status eq 'active'"), + new("$top", "10"), + }; + + var result = QueryStringBuilder.Build(parameters); + + Assert.That(result, Does.Contain("$filter=status%20eq%20'active'")); + Assert.That(result, Does.Contain("$top=10")); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/QueryStringConverterTests.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/QueryStringConverterTests.cs new file mode 100644 index 000000000000..d73c8df94238 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/QueryStringConverterTests.cs @@ -0,0 +1,158 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core; + +[TestFixture] +public class QueryStringConverterTests +{ + [Test] + public void ToQueryStringCollection_Form() + { + var obj = new + { + Name = "John", + Age = 30, + Address = new + { + Street = "123 Main St", + City = "Anytown", + Coordinates = new[] { 39.781721f, -89.650148f }, + }, + Tags = new[] { "Developer", "Blogger" }, + }; + var result = QueryStringConverter.ToForm(obj); + var expected = new List> + { + new("Name", "John"), + new("Age", "30"), + new("Address[Street]", "123 Main St"), + new("Address[City]", "Anytown"), + new("Address[Coordinates]", "39.78172,-89.65015"), + new("Tags", "Developer,Blogger"), + }; + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void ToQueryStringCollection_ExplodedForm() + { + var obj = new + { + Name = "John", + Age = 30, + Address = new + { + Street = "123 Main St", + City = "Anytown", + Coordinates = new[] { 39.781721f, -89.650148f }, + }, + Tags = new[] { "Developer", "Blogger" }, + }; + var result = QueryStringConverter.ToExplodedForm(obj); + var expected = new List> + { + new("Name", "John"), + new("Age", "30"), + new("Address[Street]", "123 Main St"), + new("Address[City]", "Anytown"), + new("Address[Coordinates]", "39.78172"), + new("Address[Coordinates]", "-89.65015"), + new("Tags", "Developer"), + new("Tags", "Blogger"), + }; + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void ToQueryStringCollection_DeepObject() + { + var obj = new + { + Name = "John", + Age = 30, + Address = new + { + Street = "123 Main St", + City = "Anytown", + Coordinates = new[] { 39.781721f, -89.650148f }, + }, + Tags = new[] { "Developer", "Blogger" }, + }; + var result = QueryStringConverter.ToDeepObject(obj); + var expected = new List> + { + new("Name", "John"), + new("Age", "30"), + new("Address[Street]", "123 Main St"), + new("Address[City]", "Anytown"), + new("Address[Coordinates][0]", "39.78172"), + new("Address[Coordinates][1]", "-89.65015"), + new("Tags[0]", "Developer"), + new("Tags[1]", "Blogger"), + }; + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void ToQueryStringCollection_OnString_ThrowsException() + { + var exception = Assert.Throws(() => + QueryStringConverter.ToForm("invalid") + ); + Assert.That( + exception.Message, + Is.EqualTo( + "Only objects can be converted to query string collections. Given type is String." + ) + ); + } + + [Test] + public void ToQueryStringCollection_OnArray_ThrowsException() + { + var exception = Assert.Throws(() => + QueryStringConverter.ToForm(Array.Empty()) + ); + Assert.That( + exception.Message, + Is.EqualTo( + "Only objects can be converted to query string collections. Given type is Array." + ) + ); + } + + [Test] + public void ToQueryStringCollection_DeepObject_WithPrefix() + { + var obj = new + { + custom_session_id = "my-id", + system_prompt = "You are helpful", + variables = new { name = "Alice", age = 25 }, + }; + var result = QueryStringConverter.ToDeepObject("session_settings", obj); + var expected = new List> + { + new("session_settings[custom_session_id]", "my-id"), + new("session_settings[system_prompt]", "You are helpful"), + new("session_settings[variables][name]", "Alice"), + new("session_settings[variables][age]", "25"), + }; + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void ToQueryStringCollection_ExplodedForm_WithPrefix() + { + var obj = new { Name = "John", Tags = new[] { "Developer", "Blogger" } }; + var result = QueryStringConverter.ToExplodedForm("user", obj); + var expected = new List> + { + new("user[Name]", "John"), + new("user[Tags]", "Developer"), + new("user[Tags]", "Blogger"), + }; + Assert.That(result, Is.EqualTo(expected)); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/GzipResponseTests.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/GzipResponseTests.cs new file mode 100644 index 000000000000..d3530f3708b1 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/GzipResponseTests.cs @@ -0,0 +1,104 @@ +using global::System.IO.Compression; +using global::System.Net.Http; +using global::System.Text; +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; +using WireMock.Server; +using SystemTask = global::System.Threading.Tasks.Task; +using WireMockRequest = WireMock.RequestBuilders.Request; +using WireMockResponse = WireMock.ResponseBuilders.Response; + +namespace SeedCsharpXmlEntities.Test.Core.RawClientTests; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class GzipResponseTests +{ + private WireMockServer _server; + private RawClient _rawClient; + private string _baseUrl; + + [SetUp] + public void SetUp() + { + _server = WireMockServer.Start(); + _baseUrl = _server.Url ?? ""; + _rawClient = new RawClient(new ClientOptions { MaxRetries = 0 }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldDecompressGzipResponse() + { + const string body = "{\"message\": \"gzipped response\"}"; + _server + .Given( + WireMockRequest + .Create() + .WithPath("/gzip") + .WithHeader("Accept-Encoding", "gzip*") + .UsingGet() + ) + .RespondWith( + WireMockResponse + .Create() + .WithStatusCode(200) + .WithHeader("Content-Encoding", "gzip") + .WithBody(Compress(body)) + ); + + var request = new SeedCsharpXmlEntities.Core.EmptyRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/gzip", + Headers = new Dictionary { ["Accept-Encoding"] = "gzip" }, + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.That(content, Is.EqualTo(body)); + Assert.That(response.Raw.Content.Headers.ContentEncoding, Is.Empty); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldReturnUncompressedResponseUnchanged() + { + const string body = "{\"message\": \"plain response\"}"; + _server + .Given(WireMockRequest.Create().WithPath("/plain").UsingGet()) + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody(body)); + + var request = new SeedCsharpXmlEntities.Core.EmptyRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/plain", + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.That(content, Is.EqualTo(body)); + } + + private static byte[] Compress(string value) + { + using var output = new MemoryStream(); + using (var gzipStream = new GZipStream(output, CompressionMode.Compress)) + { + var bytes = Encoding.UTF8.GetBytes(value); + gzipStream.Write(bytes, 0, bytes.Length); + } + return output.ToArray(); + } + + [TearDown] + public void TearDown() + { + _server.Stop(); + _server.Dispose(); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/MultipartFormTests.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/MultipartFormTests.cs new file mode 100644 index 000000000000..bf44cacdf0a2 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/MultipartFormTests.cs @@ -0,0 +1,1121 @@ +using global::System.Net.Http; +using global::System.Text; +using global::System.Text.Json.Serialization; +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; +using SystemTask = global::System.Threading.Tasks.Task; + +namespace SeedCsharpXmlEntities.Test.Core.RawClientTests; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class MultipartFormTests +{ + private static SimpleObject _simpleObject = new(); + + private static string _simpleFormEncoded = + "meta=data&Date=2023-10-01&Time=12:00:00&Duration=01:00:00&Id=1a1bb98f-47c6-407b-9481-78476affe52a&IsActive=true&Count=42&Initial=A&Values=data,2023-10-01,12:00:00,01:00:00,1a1bb98f-47c6-407b-9481-78476affe52a,true,42,A"; + + private static string _simpleExplodedFormEncoded = + "meta=data&Date=2023-10-01&Time=12:00:00&Duration=01:00:00&Id=1a1bb98f-47c6-407b-9481-78476affe52a&IsActive=true&Count=42&Initial=A&Values=data&Values=2023-10-01&Values=12:00:00&Values=01:00:00&Values=1a1bb98f-47c6-407b-9481-78476affe52a&Values=true&Values=42&Values=A"; + + private static ComplexObject _complexObject = new(); + + private static string _complexJson = """ + { + "meta": "data", + "Nested": { + "foo": "value" + }, + "NestedDictionary": { + "key": { + "foo": "value" + } + }, + "ListOfObjects": [ + { + "foo": "value" + }, + { + "foo": "value2" + } + ], + "Date": "2023-10-01", + "Time": "12:00:00", + "Duration": "01:00:00", + "Id": "1a1bb98f-47c6-407b-9481-78476affe52a", + "IsActive": true, + "Count": 42, + "Initial": "A" + } + """; + + [Test] + public async SystemTask ShouldAddStringPart() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringPart("string", partInput); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=string + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddStringParts() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringParts("strings", [partInput, partInput]); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask GivenNull_ShouldNotAddStringPart() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringPart("string", null); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddStringParts_WithNullsInList() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringParts("strings", [partInput, null, partInput]); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddStringPart_WithContentType() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringPart("string", partInput, "text/xml"); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/xml + Content-Disposition: form-data; name=string + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddStringPart_WithContentTypeAndCharset() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringPart("string", partInput, "text/xml; charset=utf-8"); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/xml; charset=utf-8 + Content-Disposition: form-data; name=string + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddStringParts_WithContentType() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringParts("strings", [partInput, partInput], "text/xml"); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/xml + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary} + Content-Type: text/xml + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddStringParts_WithContentTypeAndCharset() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringParts( + "strings", + [partInput, partInput], + "text/xml; charset=utf-8" + ); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/xml; charset=utf-8 + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary} + Content-Type: text/xml; charset=utf-8 + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameter_WithFileName() + { + var (partInput, partExpectedString) = GetFileParameterTestData(); + var file = new FileParameter { Stream = partInput, FileName = "test.txt" }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", file); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/octet-stream + Content-Disposition: form-data; name=file; filename=test.txt; filename*=utf-8''test.txt + + {partExpectedString} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameter_WithoutFileName() + { + var (partInput, partExpectedString) = GetFileParameterTestData(); + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", partInput); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/octet-stream + Content-Disposition: form-data; name=file + + {partExpectedString} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameter_WithContentType() + { + var (partInput, partExpectedString) = GetFileParameterTestData(); + var file = new FileParameter + { + Stream = partInput, + FileName = "test.txt", + ContentType = "text/plain", + }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", file, "ignored-fallback-content-type"); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=file; filename=test.txt; filename*=utf-8''test.txt + + {partExpectedString} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameter_WithContentTypeAndCharset() + { + var (partInput, partExpectedString) = GetFileParameterTestData(); + var file = new FileParameter + { + Stream = partInput, + FileName = "test.txt", + ContentType = "text/plain; charset=utf-8", + }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", file, "ignored-fallback-content-type"); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain; charset=utf-8 + Content-Disposition: form-data; name=file; filename=test.txt; filename*=utf-8''test.txt + + {partExpectedString} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameter_WithFallbackContentType() + { + var (partInput, partExpectedString) = GetFileParameterTestData(); + var file = new FileParameter { Stream = partInput, FileName = "test.txt" }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", file, "text/plain"); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=file; filename=test.txt; filename*=utf-8''test.txt + + {partExpectedString} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameter_WithFallbackContentTypeAndCharset() + { + var (partInput, partExpectedString) = GetFileParameterTestData(); + var file = new FileParameter { Stream = partInput, FileName = "test.txt" }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", file, "text/plain; charset=utf-8"); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain; charset=utf-8 + Content-Disposition: form-data; name=file; filename=test.txt; filename*=utf-8''test.txt + + {partExpectedString} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameters() + { + var (partInput1, partExpectedString1) = GetFileParameterTestData(); + var (partInput2, partExpectedString2) = GetFileParameterTestData(); + var file1 = new FileParameter { Stream = partInput1, FileName = "test1.txt" }; + var file2 = new FileParameter { Stream = partInput2, FileName = "test2.txt" }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterParts("file", [file1, file2]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/octet-stream + Content-Disposition: form-data; name=file; filename=test1.txt; filename*=utf-8''test1.txt + + {partExpectedString1} + --{boundary} + Content-Type: application/octet-stream + Content-Disposition: form-data; name=file; filename=test2.txt; filename*=utf-8''test2.txt + + {partExpectedString2} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameters_WithNullsInList() + { + var (partInput1, partExpectedString1) = GetFileParameterTestData(); + var (partInput2, partExpectedString2) = GetFileParameterTestData(); + var file1 = new FileParameter { Stream = partInput1, FileName = "test1.txt" }; + var file2 = new FileParameter { Stream = partInput2, FileName = "test2.txt" }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterParts("file", [file1, null, file2]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/octet-stream + Content-Disposition: form-data; name=file; filename=test1.txt; filename*=utf-8''test1.txt + + {partExpectedString1} + --{boundary} + Content-Type: application/octet-stream + Content-Disposition: form-data; name=file; filename=test2.txt; filename*=utf-8''test2.txt + + {partExpectedString2} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask GivenNull_ShouldNotAddFileParameter() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", null); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddJsonPart_WithComplexObject() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddJsonPart("object", _complexObject); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/json + Content-Disposition: form-data; name=object + + {_complexJson} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddJsonPart_WithComplexObjectList() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddJsonParts("objects", [_complexObject, _complexObject]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/json + Content-Disposition: form-data; name=objects + + {_complexJson} + --{boundary} + Content-Type: application/json + Content-Disposition: form-data; name=objects + + {_complexJson} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask GivenNull_ShouldNotAddJsonPart() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddJsonPart("object", null); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddJsonParts_WithNullsInList() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddJsonParts("objects", [_complexObject, null]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/json + Content-Disposition: form-data; name=objects + + {_complexJson} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddJsonParts_WithContentType() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddJsonParts("objects", [new { }], "application/json-patch+json"); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $$""" + --{{boundary}} + Content-Type: application/json-patch+json + Content-Disposition: form-data; name=objects + + {} + --{{boundary}}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFormEncodedParts_WithSimpleObject() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedPart("object", _simpleObject); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=object + + {EscapeFormEncodedString(_simpleFormEncoded)} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFormEncodedParts_WithSimpleObjectList() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedParts("objects", [_simpleObject, _simpleObject]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + {EscapeFormEncodedString(_simpleFormEncoded)} + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + {EscapeFormEncodedString(_simpleFormEncoded)} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldNotAddFormEncodedParts_WithNull() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedParts("object", null); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldNotAddFormEncodedParts_WithNullsInList() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedParts("objects", [_simpleObject, null]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + {EscapeFormEncodedString(_simpleFormEncoded)} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFormEncodedPart_WithContentType() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedPart( + "objects", + new { foo = "bar" }, + "application/x-www-form-urlencoded" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFormEncodedPart_WithContentTypeAndCharset() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedPart( + "objects", + new { foo = "bar" }, + "application/x-www-form-urlencoded; charset=utf-8" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded; charset=utf-8 + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFormEncodedParts_WithContentType() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedParts( + "objects", + [new { foo = "bar" }], + "application/x-www-form-urlencoded" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFormEncodedParts_WithContentTypeAndCharset() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedParts( + "objects", + [new { foo = "bar" }], + "application/x-www-form-urlencoded; charset=utf-8" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded; charset=utf-8 + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddExplodedFormEncodedParts_WithSimpleObject() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedPart("object", _simpleObject); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=object + + {EscapeFormEncodedString(_simpleExplodedFormEncoded)} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddExplodedFormEncodedParts_WithSimpleObjectList() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedParts("objects", [_simpleObject, _simpleObject]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + {EscapeFormEncodedString(_simpleExplodedFormEncoded)} + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + {EscapeFormEncodedString(_simpleExplodedFormEncoded)} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldNotAddExplodedFormEncodedParts_WithNull() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedPart("object", null); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldNotAddExplodedFormEncodedParts_WithNullsInList() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedParts("objects", [_simpleObject, null]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + {EscapeFormEncodedString(_simpleExplodedFormEncoded)} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddExplodedFormEncodedPart_WithContentType() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedPart( + "objects", + new { foo = "bar" }, + "application/x-www-form-urlencoded" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddExplodedFormEncodedPart_WithContentTypeAndCharset() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedPart( + "objects", + new { foo = "bar" }, + "application/x-www-form-urlencoded; charset=utf-8" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded; charset=utf-8 + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddExplodedFormEncodedParts_WithContentType() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedParts( + "objects", + [new { foo = "bar" }], + "application/x-www-form-urlencoded" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddExplodedFormEncodedParts_WithContentTypeAndCharset() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedParts( + "objects", + [new { foo = "bar" }], + "application/x-www-form-urlencoded; charset=utf-8" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded; charset=utf-8 + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + private static string EscapeFormEncodedString(string input) + { + return string.Join( + "&", + input + .Split('&') + .Select(x => x.Split('=')) + .Select(x => $"{Uri.EscapeDataString(x[0])}={Uri.EscapeDataString(x[1])}") + ); + } + + private static string GetBoundary(MultipartFormDataContent content) + { + return content + .Headers.ContentType?.Parameters.Single(p => + p.Name.Equals("boundary", StringComparison.OrdinalIgnoreCase) + ) + .Value?.Trim('"') + ?? throw new global::System.Exception("Boundary not found"); + } + + private static SeedCsharpXmlEntities.Core.MultipartFormRequest CreateMultipartFormRequest() + { + return new SeedCsharpXmlEntities.Core.MultipartFormRequest + { + BaseUrl = "https://localhost", + Method = HttpMethod.Post, + Path = "", + }; + } + + private static (Stream partInput, string partExpectedString) GetFileParameterTestData() + { + const string partExpectedString = "file content"; + var partInput = new MemoryStream(Encoding.Default.GetBytes(partExpectedString)); + return (partInput, partExpectedString); + } + + private class SimpleObject + { + [JsonPropertyName("meta")] + public string Meta { get; set; } = "data"; + public DateOnly Date { get; set; } = DateOnly.Parse("2023-10-01"); + public TimeOnly Time { get; set; } = TimeOnly.Parse("12:00:00"); + public TimeSpan Duration { get; set; } = TimeSpan.FromHours(1); + public Guid Id { get; set; } = Guid.Parse("1a1bb98f-47c6-407b-9481-78476affe52a"); + public bool IsActive { get; set; } = true; + public int Count { get; set; } = 42; + public char Initial { get; set; } = 'A'; + public IEnumerable Values { get; set; } = + [ + "data", + DateOnly.Parse("2023-10-01"), + TimeOnly.Parse("12:00:00"), + TimeSpan.FromHours(1), + Guid.Parse("1a1bb98f-47c6-407b-9481-78476affe52a"), + true, + 42, + 'A', + ]; + } + + private class ComplexObject + { + [JsonPropertyName("meta")] + public string Meta { get; set; } = "data"; + + public object Nested { get; set; } = new { foo = "value" }; + + public Dictionary NestedDictionary { get; set; } = + new() { { "key", new { foo = "value" } } }; + + public IEnumerable ListOfObjects { get; set; } = + new List { new { foo = "value" }, new { foo = "value2" } }; + + public DateOnly Date { get; set; } = DateOnly.Parse("2023-10-01"); + public TimeOnly Time { get; set; } = TimeOnly.Parse("12:00:00"); + public TimeSpan Duration { get; set; } = TimeSpan.FromHours(1); + public Guid Id { get; set; } = Guid.Parse("1a1bb98f-47c6-407b-9481-78476affe52a"); + public bool IsActive { get; set; } = true; + public int Count { get; set; } = 42; + public char Initial { get; set; } = 'A'; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/QueryParameterTests.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/QueryParameterTests.cs new file mode 100644 index 000000000000..fb84851bc98a --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/QueryParameterTests.cs @@ -0,0 +1,108 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core.RawClientTests; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class QueryParameterTests +{ + [Test] + public void QueryParameters_BasicParameters() + { + var queryString = new QueryStringBuilder.Builder() + .Add("foo", "bar") + .Add("baz", "qux") + .Build(); + + Assert.That(queryString, Is.EqualTo("?foo=bar&baz=qux")); + } + + [Test] + public void QueryParameters_SpecialCharacterEscaping() + { + var queryString = new QueryStringBuilder.Builder() + .Add("email", "bob+test@example.com") + .Add("%Complete", "100") + .Add("space test", "hello world") + .Build(); + + Assert.That(queryString, Does.Contain("email=bob%2Btest@example.com")); + Assert.That(queryString, Does.Contain("%25Complete=100")); + Assert.That(queryString, Does.Contain("space%20test=hello%20world")); + } + + [Test] + public void QueryParameters_MergeAdditionalParameters() + { + var queryString = new QueryStringBuilder.Builder() + .Add("sdk", "param") + .MergeAdditional(new List> { new("user", "value") }) + .Build(); + + Assert.That(queryString, Does.Contain("sdk=param")); + Assert.That(queryString, Does.Contain("user=value")); + } + + [Test] + public void QueryParameters_AdditionalOverridesSdk() + { + var queryString = new QueryStringBuilder.Builder() + .Add("foo", "sdk_value") + .MergeAdditional(new List> { new("foo", "user_override") }) + .Build(); + + Assert.That(queryString, Does.Contain("foo=user_override")); + Assert.That(queryString, Does.Not.Contain("sdk_value")); + } + + [Test] + public void QueryParameters_AdditionalMultipleValues() + { + var queryString = new QueryStringBuilder.Builder() + .Add("foo", "sdk_value") + .MergeAdditional( + new List> { new("foo", "user1"), new("foo", "user2") } + ) + .Build(); + + Assert.That(queryString, Does.Contain("foo=user1")); + Assert.That(queryString, Does.Contain("foo=user2")); + Assert.That(queryString, Does.Not.Contain("sdk_value")); + } + + [Test] + public void QueryParameters_OnlyAdditionalParameters() + { + var queryString = new QueryStringBuilder.Builder() + .MergeAdditional( + new List> { new("foo", "bar"), new("baz", "qux") } + ) + .Build(); + + Assert.That(queryString, Does.Contain("foo=bar")); + Assert.That(queryString, Does.Contain("baz=qux")); + } + + [Test] + public void QueryParameters_EmptyAdditionalParameters() + { + var queryString = new QueryStringBuilder.Builder() + .Add("foo", "bar") + .MergeAdditional(new List>()) + .Build(); + + Assert.That(queryString, Is.EqualTo("?foo=bar")); + } + + [Test] + public void QueryParameters_NullAdditionalParameters() + { + var queryString = new QueryStringBuilder.Builder() + .Add("foo", "bar") + .MergeAdditional(null) + .Build(); + + Assert.That(queryString, Is.EqualTo("?foo=bar")); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/RetriesTests.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/RetriesTests.cs new file mode 100644 index 000000000000..99bd5a2ae53d --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/RetriesTests.cs @@ -0,0 +1,540 @@ +using global::System.Net.Http; +using global::System.Text.Json; +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; +using WireMock.Server; +using SystemTask = global::System.Threading.Tasks.Task; +using WireMockRequest = WireMock.RequestBuilders.Request; +using WireMockResponse = WireMock.ResponseBuilders.Response; + +namespace SeedCsharpXmlEntities.Test.Core.RawClientTests; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class RetriesTests +{ + private const int MaxRetries = 3; + private WireMockServer _server; + private HttpClient _httpClient; + private RawClient _rawClient; + private string _baseUrl; + + [SetUp] + public void SetUp() + { + _server = WireMockServer.Start(); + _baseUrl = _server.Url ?? ""; + _httpClient = new HttpClient { BaseAddress = new Uri(_baseUrl) }; + _rawClient = new RawClient( + new ClientOptions { HttpClient = _httpClient, MaxRetries = MaxRetries } + ) + { + BaseRetryDelay = 0, + }; + } + + [Test] + [TestCase(408)] + [TestCase(429)] + [TestCase(500)] + [TestCase(504)] + public async SystemTask SendRequestAsync_ShouldRetry_OnRetryableStatusCodes(int statusCode) + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("Retry") + .WillSetStateTo("Server Error") + .RespondWith(WireMockResponse.Create().WithStatusCode(statusCode)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("Retry") + .WhenStateIs("Server Error") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(statusCode)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("Retry") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.EmptyRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/test", + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + using (Assert.EnterMultipleScope()) + { + Assert.That(content, Is.EqualTo("Success")); + + Assert.That(_server.LogEntries, Has.Count.EqualTo(MaxRetries)); + } + } + + [Test] + [TestCase(400)] + [TestCase(409)] + public async SystemTask SendRequestAsync_ShouldRetry_OnNonRetryableStatusCodes(int statusCode) + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("Retry") + .WillSetStateTo("Server Error") + .RespondWith(WireMockResponse.Create().WithStatusCode(statusCode).WithBody("Failure")); + + var request = new SeedCsharpXmlEntities.Core.JsonRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/test", + Body = new { }, + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(statusCode)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Failure")); + + Assert.That(_server.LogEntries, Has.Count.EqualTo(1)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldNotRetry_WithStreamRequest() + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("Retry") + .WillSetStateTo("Server Error") + .RespondWith(WireMockResponse.Create().WithStatusCode(429).WithBody("Failure")); + + var request = new SeedCsharpXmlEntities.Core.StreamRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + Body = new MemoryStream(), + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(429)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Failure")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(1)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldNotRetry_WithMultiPartFormRequest_WithStream() + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("Retry") + .WillSetStateTo("Server Error") + .RespondWith(WireMockResponse.Create().WithStatusCode(429).WithBody("Failure")); + + var request = new SeedCsharpXmlEntities.Core.MultipartFormRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + }; + request.AddFileParameterPart("file", new MemoryStream()); + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(429)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Failure")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(1)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldRetry_WithMultiPartFormRequest_WithoutStream() + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("Retry") + .WillSetStateTo("Server Error") + .RespondWith(WireMockResponse.Create().WithStatusCode(429)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("Retry") + .WhenStateIs("Server Error") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(429)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("Retry") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.MultipartFormRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + }; + request.AddJsonPart("object", new { }); + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(MaxRetries)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldRespectRetryAfterHeader_WithSecondsValue() + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("RetryAfter") + .WillSetStateTo("Success") + .RespondWith( + WireMockResponse.Create().WithStatusCode(429).WithHeader("Retry-After", "1") + ); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("RetryAfter") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.EmptyRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/test", + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(2)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldRespectRetryAfterHeader_WithHttpDateValue() + { + var retryAfterDate = DateTimeOffset.UtcNow.AddSeconds(1).ToString("R"); + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("RetryAfterDate") + .WillSetStateTo("Success") + .RespondWith( + WireMockResponse + .Create() + .WithStatusCode(429) + .WithHeader("Retry-After", retryAfterDate) + ); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("RetryAfterDate") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.EmptyRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/test", + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(2)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldRespectXRateLimitResetHeader() + { + var resetTime = DateTimeOffset.UtcNow.AddSeconds(1).ToUnixTimeSeconds().ToString(); + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("RateLimitReset") + .WillSetStateTo("Success") + .RespondWith( + WireMockResponse + .Create() + .WithStatusCode(429) + .WithHeader("X-RateLimit-Reset", resetTime) + ); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("RateLimitReset") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.EmptyRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/test", + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(2)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldPreserveJsonBody_OnRetry() + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("RetryWithBody") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(500)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("RetryWithBody") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.JsonRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + Body = new { key = "value" }, + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + using (Assert.EnterMultipleScope()) + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(2)); + + // Verify the retried request preserved the JSON body (compare parsed to ignore formatting differences) + var retriedEntry = _server.LogEntries.ElementAt(1); + using var actualJson = JsonDocument.Parse(retriedEntry.RequestMessage.Body!); + Assert.That(actualJson.RootElement.GetProperty("key").GetString(), Is.EqualTo("value")); + } + } + + [Test] + public async SystemTask SendRequestAsync_ShouldPreserveMultipartBody_OnRetry() + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("RetryMultipart") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(500)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("RetryMultipart") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.MultipartFormRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + }; + request.AddJsonPart("object", new { key = "value" }); + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + using (Assert.EnterMultipleScope()) + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(2)); + + // Verify the retried request preserved the multipart body (check key/value presence to ignore formatting differences) + var retriedEntry = _server.LogEntries.ElementAt(1); + Assert.That(retriedEntry.RequestMessage.Body, Does.Contain("\"key\"")); + Assert.That(retriedEntry.RequestMessage.Body, Does.Contain("\"value\"")); + } + } + + [Test] + public async SystemTask SendRequestAsync_ShouldRetry_WhenHandlerDisposesRequestContent() + { + // ContentDisposingHandler simulates HTTP/2's disposal of request.Content after send; + // WireMock's loopback HTTP/1.1 path does not exhibit that on its own. + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("DisposeContentRetry") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(500)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("DisposeContentRetry") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + using var disposingClient = new HttpClient( + new ContentDisposingHandler(new HttpClientHandler()) + ); + var rawClient = new RawClient( + new ClientOptions { HttpClient = disposingClient, MaxRetries = MaxRetries } + ) + { + BaseRetryDelay = 0, + }; + + var request = new SeedCsharpXmlEntities.Core.JsonRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + Body = new { key = "value" }, + }; + + var response = await rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + using (Assert.EnterMultipleScope()) + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(2)); + + var retriedEntry = _server.LogEntries.ElementAt(1); + using var actualJson = JsonDocument.Parse(retriedEntry.RequestMessage.Body!); + Assert.That(actualJson.RootElement.GetProperty("key").GetString(), Is.EqualTo("value")); + } + } + + [Test] + public async SystemTask SendRequestAsync_ShouldRetry_WhenHandlerDisposesRequestContent_AcrossMultipleRetries() + { + // Exercises 2nd and 3rd clones — the single-retry variant can pass if those break. + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("DisposeContentMultiRetry") + .WillSetStateTo("Second") + .RespondWith(WireMockResponse.Create().WithStatusCode(500)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("DisposeContentMultiRetry") + .WhenStateIs("Second") + .WillSetStateTo("Third") + .RespondWith(WireMockResponse.Create().WithStatusCode(500)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("DisposeContentMultiRetry") + .WhenStateIs("Third") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(500)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("DisposeContentMultiRetry") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + using var disposingClient = new HttpClient( + new ContentDisposingHandler(new HttpClientHandler()) + ); + var rawClient = new RawClient( + new ClientOptions { HttpClient = disposingClient, MaxRetries = MaxRetries } + ) + { + BaseRetryDelay = 0, + }; + + var request = new SeedCsharpXmlEntities.Core.JsonRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + Body = new { key = "value" }, + }; + + var response = await rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + using (Assert.EnterMultipleScope()) + { + // Initial attempt + 3 retries == 4 requests reaching the server. + Assert.That(_server.LogEntries, Has.Count.EqualTo(MaxRetries + 1)); + + // Every retried request must have preserved the original body. + foreach (var entry in _server.LogEntries) + { + using var actualJson = JsonDocument.Parse(entry.RequestMessage.Body!); + Assert.That( + actualJson.RootElement.GetProperty("key").GetString(), + Is.EqualTo("value") + ); + } + } + } + + [TearDown] + public void TearDown() + { + _server.Dispose(); + _httpClient.Dispose(); + } + + private sealed class ContentDisposingHandler : DelegatingHandler + { + public ContentDisposingHandler(HttpMessageHandler inner) + : base(inner) { } + + protected override async global::System.Threading.Tasks.Task SendAsync( + HttpRequestMessage request, + CancellationToken cancellationToken + ) + { + var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false); + request.Content?.Dispose(); + return response; + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/WithRawResponseTests.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/WithRawResponseTests.cs new file mode 100644 index 000000000000..355677943b0c --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Core/WithRawResponseTests.cs @@ -0,0 +1,269 @@ +using global::System.Net; +using global::System.Net.Http.Headers; +using NUnit.Framework; +using SeedCsharpXmlEntities; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core; + +[TestFixture] +public class WithRawResponseTests +{ + [Test] + public async global::System.Threading.Tasks.Task WithRawResponseTask_DirectAwait_ReturnsData() + { + // Arrange + var expectedData = "test-data"; + var task = CreateWithRawResponseTask(expectedData, HttpStatusCode.OK); + + // Act + var result = await task; + + // Assert + Assert.That(result, Is.EqualTo(expectedData)); + } + + [Test] + public async global::System.Threading.Tasks.Task WithRawResponseTask_WithRawResponse_ReturnsDataAndMetadata() + { + // Arrange + var expectedData = "test-data"; + var expectedStatusCode = HttpStatusCode.Created; + var task = CreateWithRawResponseTask(expectedData, expectedStatusCode); + + // Act + var result = await task.WithRawResponse(); + + // Assert + Assert.That(result.Data, Is.EqualTo(expectedData)); + Assert.That(result.RawResponse.StatusCode, Is.EqualTo(expectedStatusCode)); + Assert.That(result.RawResponse.Url, Is.Not.Null); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_TryGetValue_CaseInsensitive() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + response.Headers.Add("X-Request-Id", "12345"); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act & Assert + Assert.That(headers.TryGetValue("X-Request-Id", out var value), Is.True); + Assert.That(value, Is.EqualTo("12345")); + + Assert.That(headers.TryGetValue("x-request-id", out value), Is.True); + Assert.That(value, Is.EqualTo("12345")); + + Assert.That(headers.TryGetValue("X-REQUEST-ID", out value), Is.True); + Assert.That(value, Is.EqualTo("12345")); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_TryGetValues_ReturnsMultipleValues() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + response.Headers.Add("Set-Cookie", new[] { "cookie1=value1", "cookie2=value2" }); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act + var success = headers.TryGetValues("Set-Cookie", out var values); + + // Assert + Assert.That(success, Is.True); + Assert.That(values, Is.Not.Null); + Assert.That(values!.Count(), Is.EqualTo(2)); + Assert.That(values, Does.Contain("cookie1=value1")); + Assert.That(values, Does.Contain("cookie2=value2")); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_ContentType_ReturnsValue() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + response.Content = new StringContent( + "{}", + global::System.Text.Encoding.UTF8, + "application/json" + ); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act + var contentType = headers.ContentType; + + // Assert + Assert.That(contentType, Is.Not.Null); + Assert.That(contentType, Does.Contain("application/json")); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_ContentLength_ReturnsValue() + { + // Arrange + var content = "test content"; + using var response = CreateHttpResponse(HttpStatusCode.OK); + response.Content = new StringContent(content); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act + var contentLength = headers.ContentLength; + + // Assert + Assert.That(contentLength, Is.Not.Null); + Assert.That(contentLength, Is.GreaterThan(0)); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_Contains_ReturnsTrueForExistingHeader() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + response.Headers.Add("X-Custom-Header", "value"); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act & Assert + Assert.That(headers.Contains("X-Custom-Header"), Is.True); + Assert.That(headers.Contains("x-custom-header"), Is.True); + Assert.That(headers.Contains("NonExistent"), Is.False); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_Enumeration_IncludesAllHeaders() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + response.Headers.Add("X-Header-1", "value1"); + response.Headers.Add("X-Header-2", "value2"); + response.Content = new StringContent("test"); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act + var allHeaders = headers.ToList(); + + // Assert + Assert.That(allHeaders.Count, Is.GreaterThan(0)); + Assert.That(allHeaders.Any(h => h.Name == "X-Header-1"), Is.True); + Assert.That(allHeaders.Any(h => h.Name == "X-Header-2"), Is.True); + } + + [Test] + public async global::System.Threading.Tasks.Task WithRawResponseTask_ErrorStatusCode_StillReturnsMetadata() + { + // Arrange + var expectedData = "error-data"; + var task = CreateWithRawResponseTask(expectedData, HttpStatusCode.BadRequest); + + // Act + var result = await task.WithRawResponse(); + + // Assert + Assert.That(result.Data, Is.EqualTo(expectedData)); + Assert.That(result.RawResponse.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest)); + } + + [Test] + public async global::System.Threading.Tasks.Task WithRawResponseTask_Url_IsPreserved() + { + // Arrange + var expectedUrl = new Uri("https://api.example.com/users/123"); + var task = CreateWithRawResponseTask("data", HttpStatusCode.OK, expectedUrl); + + // Act + var result = await task.WithRawResponse(); + + // Assert + Assert.That(result.RawResponse.Url, Is.EqualTo(expectedUrl)); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_TryGetValue_NonExistentHeader_ReturnsFalse() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act + var success = headers.TryGetValue("X-NonExistent", out var value); + + // Assert + Assert.That(success, Is.False); + Assert.That(value, Is.Null); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_TryGetValues_NonExistentHeader_ReturnsFalse() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act + var success = headers.TryGetValues("X-NonExistent", out var values); + + // Assert + Assert.That(success, Is.False); + Assert.That(values, Is.Null); + } + + [Test] + public async global::System.Threading.Tasks.Task WithRawResponseTask_ImplicitConversion_ToTask() + { + // Arrange + var expectedData = "test-data"; + var task = CreateWithRawResponseTask(expectedData, HttpStatusCode.OK); + + // Act - implicitly convert to Task + global::System.Threading.Tasks.Task regularTask = task; + var result = await regularTask; + + // Assert + Assert.That(result, Is.EqualTo(expectedData)); + } + + [Test] + public void WithRawResponseTask_ImplicitConversion_AssignToTaskVariable() + { + // Arrange + var expectedData = "test-data"; + var wrappedTask = CreateWithRawResponseTask(expectedData, HttpStatusCode.OK); + + // Act - assign to Task variable + global::System.Threading.Tasks.Task regularTask = wrappedTask; + + // Assert + Assert.That(regularTask, Is.Not.Null); + Assert.That(regularTask, Is.InstanceOf>()); + } + + // Helper methods + + private static WithRawResponseTask CreateWithRawResponseTask( + T data, + HttpStatusCode statusCode, + Uri? url = null + ) + { + url ??= new Uri("https://api.example.com/test"); + using var httpResponse = CreateHttpResponse(statusCode); + httpResponse.RequestMessage = new HttpRequestMessage(HttpMethod.Get, url); + + var rawResponse = new RawResponse + { + StatusCode = statusCode, + Url = url, + Headers = ResponseHeaders.FromHttpResponseMessage(httpResponse), + }; + + var withRawResponse = new WithRawResponse { Data = data, RawResponse = rawResponse }; + + var task = global::System.Threading.Tasks.Task.FromResult(withRawResponse); + return new WithRawResponseTask(task); + } + + private static HttpResponseMessage CreateHttpResponse(HttpStatusCode statusCode) + { + return new HttpResponseMessage(statusCode) { Content = new StringContent("") }; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.Custom.props b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.Custom.props new file mode 100644 index 000000000000..aac9b5020d80 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.Custom.props @@ -0,0 +1,6 @@ + + diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj new file mode 100644 index 000000000000..ab37b399beed --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj @@ -0,0 +1,39 @@ + + + net9.0 + 12 + enable + enable + false + true + true + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/TestClient.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/TestClient.cs new file mode 100644 index 000000000000..f71a20870021 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/TestClient.cs @@ -0,0 +1,6 @@ +using NUnit.Framework; + +namespace SeedCsharpXmlEntities.Test; + +[TestFixture] +public class TestClient; diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Unit/MockServer/BaseMockServerTest.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Unit/MockServer/BaseMockServerTest.cs new file mode 100644 index 000000000000..91d45fe5f270 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Unit/MockServer/BaseMockServerTest.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities; +using WireMock.Logging; +using WireMock.Server; +using WireMock.Settings; + +namespace SeedCsharpXmlEntities.Test.Unit.MockServer; + +public class BaseMockServerTest +{ + protected WireMockServer Server { get; set; } = null!; + + protected SeedCsharpXmlEntitiesClient Client { get; set; } = null!; + + protected RequestOptions RequestOptions { get; set; } = new(); + + [OneTimeSetUp] + public void GlobalSetup() + { + // Start the WireMock server + Server = WireMockServer.Start( + new WireMockServerSettings { Logger = new WireMockConsoleLogger() } + ); + + // Initialize the Client + Client = new SeedCsharpXmlEntitiesClient( + clientOptions: new ClientOptions { BaseUrl = Server.Urls[0], MaxRetries = 0 } + ); + } + + [OneTimeTearDown] + public void GlobalTeardown() + { + Server.Stop(); + Server.Dispose(); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Unit/MockServer/GetTimeZoneTest.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Unit/MockServer/GetTimeZoneTest.cs new file mode 100644 index 000000000000..c960b7457afa --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Unit/MockServer/GetTimeZoneTest.cs @@ -0,0 +1,36 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Test.Utils; + +namespace SeedCsharpXmlEntities.Test.Unit.MockServer; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class GetTimeZoneTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public async Task MockServerTest() + { + const string mockResponse = """ + { + "timeZoneOffset": "timeZoneOffset", + "mathExpression": "mathExpression", + "validEntity": "validEntity", + "specialChars": "specialChars", + "documentationLink": "documentationLink", + "escapedDocumentationLink": "escapedDocumentationLink" + } + """; + + Server + .Given(WireMock.RequestBuilders.Request.Create().WithPath("/timezone").UsingGet()) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.GetTimeZoneAsync(); + JsonAssert.AreEqual(response, mockResponse); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/AdditionalPropertiesComparer.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/AdditionalPropertiesComparer.cs new file mode 100644 index 000000000000..f4dffe0f9468 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/AdditionalPropertiesComparer.cs @@ -0,0 +1,219 @@ +using global::System.Text.Json; +using NUnit.Framework.Constraints; +using SeedCsharpXmlEntities; +using SeedCsharpXmlEntities.Core; + +namespace NUnit.Framework; + +/// +/// Extensions for EqualConstraint to handle AdditionalProperties values. +/// +public static class AdditionalPropertiesComparerExtensions +{ + /// + /// Modifies the EqualConstraint to handle AdditionalProperties instances by comparing their + /// serialized JSON representations. This handles the type mismatch between native C# types + /// and JsonElement values that occur when comparing manually constructed objects with + /// deserialized objects. + /// + /// The EqualConstraint to modify. + /// The same constraint instance for method chaining. + public static EqualConstraint UsingAdditionalPropertiesComparer(this EqualConstraint constraint) + { + constraint.Using( + (x, y) => + { + if (x.Count != y.Count) + { + return false; + } + + foreach (var key in x.Keys) + { + if (!y.ContainsKey(key)) + { + return false; + } + + var xElement = JsonUtils.SerializeToElement(x[key]); + var yElement = JsonUtils.SerializeToElement(y[key]); + + if (!JsonElementsAreEqual(xElement, yElement)) + { + return false; + } + } + + return true; + } + ); + + return constraint; + } + + /// + /// Modifies the EqualConstraint to handle Dictionary<string, object?> values by comparing + /// their serialized JSON representations. This handles the type mismatch between native C# types + /// and JsonElement values that occur when comparing manually constructed objects with + /// deserialized objects. + /// + /// The EqualConstraint to modify. + /// The same constraint instance for method chaining. + public static EqualConstraint UsingObjectDictionaryComparer(this EqualConstraint constraint) + { + constraint.Using>( + (x, y) => + { + if (x.Count != y.Count) + { + return false; + } + + foreach (var key in x.Keys) + { + if (!y.ContainsKey(key)) + { + return false; + } + + var xElement = JsonUtils.SerializeToElement(x[key]); + var yElement = JsonUtils.SerializeToElement(y[key]); + + if (!JsonElementsAreEqual(xElement, yElement)) + { + return false; + } + } + + return true; + } + ); + + return constraint; + } + + internal static bool JsonElementsAreEqualPublic(JsonElement x, JsonElement y) => + JsonElementsAreEqual(x, y); + + private static bool JsonElementsAreEqual(JsonElement x, JsonElement y) + { + if (x.ValueKind != y.ValueKind) + { + return false; + } + + return x.ValueKind switch + { + JsonValueKind.Object => CompareJsonObjects(x, y), + JsonValueKind.Array => CompareJsonArrays(x, y), + JsonValueKind.String => x.GetString() == y.GetString(), + JsonValueKind.Number => x.GetDecimal() == y.GetDecimal(), + JsonValueKind.True => true, + JsonValueKind.False => true, + JsonValueKind.Null => true, + _ => false, + }; + } + + private static bool CompareJsonObjects(JsonElement x, JsonElement y) + { + var xProps = new Dictionary(); + var yProps = new Dictionary(); + + foreach (var prop in x.EnumerateObject()) + xProps[prop.Name] = prop.Value; + + foreach (var prop in y.EnumerateObject()) + yProps[prop.Name] = prop.Value; + + if (xProps.Count != yProps.Count) + { + return false; + } + + foreach (var key in xProps.Keys) + { + if (!yProps.ContainsKey(key)) + { + return false; + } + + if (!JsonElementsAreEqual(xProps[key], yProps[key])) + { + return false; + } + } + + return true; + } + + private static bool CompareJsonArrays(JsonElement x, JsonElement y) + { + var xArray = x.EnumerateArray().ToList(); + var yArray = y.EnumerateArray().ToList(); + + if (xArray.Count != yArray.Count) + { + return false; + } + + for (var i = 0; i < xArray.Count; i++) + { + if (!JsonElementsAreEqual(xArray[i], yArray[i])) + { + return false; + } + } + + return true; + } + + /// + /// Modifies the EqualConstraint to handle cross-type comparisons involving JsonElement. + /// When UsingPropertiesComparer() walks object properties and encounters a property typed as + /// 'object', the expected side may be a Dictionary<object, object?> while the actual + /// (deserialized) side is a JsonElement. These typed predicates bridge that gap by serializing + /// the non-JsonElement side and comparing JSON representations. + /// + /// Uses typed Func<TExpected, TActual, bool> predicates instead of a non-generic + /// IComparer/IEqualityComparer so that NUnit's CanCompare type check ensures these only + /// fire when one side is a JsonElement, letting UsingPropertiesComparer() handle all + /// same-type comparisons normally. + /// + /// The EqualConstraint to modify. + /// The same constraint instance for method chaining. + public static EqualConstraint UsingJsonSerializationComparer(this EqualConstraint constraint) + { + // Handle: expected is non-JsonElement, actual is JsonElement + constraint.Using( + (actualJsonElement, expectedObj) => + { + try + { + var expectedElement = JsonUtils.SerializeToElement(expectedObj); + return JsonElementsAreEqualPublic(expectedElement, actualJsonElement); + } + catch + { + return false; + } + } + ); + // Handle reverse: expected is JsonElement, actual is non-JsonElement + constraint.Using( + (actualObj, expectedJsonElement) => + { + try + { + var actualElement = JsonUtils.SerializeToElement(actualObj); + return JsonElementsAreEqualPublic(expectedJsonElement, actualElement); + } + catch + { + return false; + } + } + ); + return constraint; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/JsonAssert.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/JsonAssert.cs new file mode 100644 index 000000000000..940853a68878 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/JsonAssert.cs @@ -0,0 +1,33 @@ +using global::System.Text.Json; +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Utils; + +internal static class JsonAssert +{ + /// + /// Asserts that the serialized JSON of an object equals the expected JSON string. + /// Uses JsonElement comparison for reliable deep equality of collections and union types. + /// + internal static void AreEqual(object actual, string expectedJson) + { + var actualElement = JsonUtils.SerializeToElement(actual); + var expectedElement = JsonUtils.Deserialize(expectedJson); + Assert.That(actualElement, Is.EqualTo(expectedElement).UsingJsonElementComparer()); + } + + /// + /// Asserts that the given JSON string survives a deserialization/serialization round-trip. + /// Deserializes to T, re-serializes to get the canonical form, then verifies a second + /// round-trip produces the same canonical form (idempotency). This accounts for serializer + /// options like WhenWritingNull that may normalize the output. + /// + internal static void Roundtrips(string json) + { + var deserialized = JsonUtils.Deserialize(json); + var serialized = JsonUtils.Serialize(deserialized!); + var deserialized2 = JsonUtils.Deserialize(serialized); + AreEqual(deserialized2!, serialized); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/JsonElementComparer.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/JsonElementComparer.cs new file mode 100644 index 000000000000..36fa0e9d4ed1 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/JsonElementComparer.cs @@ -0,0 +1,243 @@ +using global::System.Text.Json; +using NUnit.Framework.Constraints; + +namespace NUnit.Framework; + +/// +/// Extensions for EqualConstraint to handle JsonElement objects. +/// +public static class JsonElementComparerExtensions +{ + /// + /// Extension method for comparing JsonElement objects in NUnit tests. + /// Property order doesn't matter, but array order does matter. + /// Includes special handling for DateTime string formats. + /// + /// The Is.EqualTo() constraint instance. + /// A constraint that can compare JsonElements with detailed diffs. + public static EqualConstraint UsingJsonElementComparer(this EqualConstraint constraint) + { + return constraint.Using(new JsonElementComparer()); + } +} + +/// +/// Equality comparer for JsonElement with detailed reporting. +/// Property order doesn't matter, but array order does matter. +/// Now includes special handling for DateTime string formats with improved null handling. +/// +public class JsonElementComparer : IEqualityComparer +{ + private string _failurePath = string.Empty; + + /// + public bool Equals(JsonElement x, JsonElement y) + { + _failurePath = string.Empty; + return CompareJsonElements(x, y, string.Empty); + } + + /// + public int GetHashCode(JsonElement obj) + { + return JsonSerializer.Serialize(obj).GetHashCode(); + } + + private bool CompareJsonElements(JsonElement x, JsonElement y, string path) + { + // If value kinds don't match, they're not equivalent + if (x.ValueKind != y.ValueKind) + { + _failurePath = $"{path}: Expected {x.ValueKind} but got {y.ValueKind}"; + return false; + } + + switch (x.ValueKind) + { + case JsonValueKind.Object: + return CompareJsonObjects(x, y, path); + + case JsonValueKind.Array: + return CompareJsonArraysInOrder(x, y, path); + + case JsonValueKind.String: + string? xStr = x.GetString(); + string? yStr = y.GetString(); + + // Handle null strings + if (xStr is null && yStr is null) + return true; + + if (xStr is null || yStr is null) + { + _failurePath = + $"{path}: Expected {(xStr is null ? "null" : $"\"{xStr}\"")} but got {(yStr is null ? "null" : $"\"{yStr}\"")}"; + return false; + } + + // Check if they are identical strings + if (xStr == yStr) + return true; + + // Try to handle DateTime strings + if (IsLikelyDateTimeString(xStr) && IsLikelyDateTimeString(yStr)) + { + if (AreEquivalentDateTimeStrings(xStr, yStr)) + return true; + } + + _failurePath = $"{path}: Expected \"{xStr}\" but got \"{yStr}\""; + return false; + + case JsonValueKind.Number: + if (x.GetDecimal() != y.GetDecimal()) + { + if (x.GetDouble() != y.GetDouble()) + { + if (x.GetSingle() != y.GetSingle()) + { + _failurePath = + $"{path}: Expected {x.GetDecimal()} but got {y.GetDecimal()}"; + return false; + } + } + } + + return true; + + case JsonValueKind.True: + case JsonValueKind.False: + if (x.GetBoolean() != y.GetBoolean()) + { + _failurePath = $"{path}: Expected {x.GetBoolean()} but got {y.GetBoolean()}"; + return false; + } + + return true; + + case JsonValueKind.Null: + return true; + + default: + _failurePath = $"{path}: Unsupported JsonValueKind {x.ValueKind}"; + return false; + } + } + + private bool IsLikelyDateTimeString(string? str) + { + // Simple heuristic to identify likely ISO date time strings + return str is not null + && (str.Contains("T") && (str.EndsWith("Z") || str.Contains("+") || str.Contains("-"))); + } + + private bool AreEquivalentDateTimeStrings(string str1, string str2) + { + // Try to parse both as DateTime + if (DateTime.TryParse(str1, out DateTime dt1) && DateTime.TryParse(str2, out DateTime dt2)) + { + return dt1 == dt2; + } + + return false; + } + + private bool CompareJsonObjects(JsonElement x, JsonElement y, string path) + { + // Create dictionaries for both JSON objects + var xProps = new Dictionary(); + var yProps = new Dictionary(); + + foreach (var prop in x.EnumerateObject()) + xProps[prop.Name] = prop.Value; + + foreach (var prop in y.EnumerateObject()) + yProps[prop.Name] = prop.Value; + + // Check if all properties in x exist in y + foreach (var key in xProps.Keys) + { + if (!yProps.ContainsKey(key)) + { + _failurePath = $"{path}: Missing property '{key}'"; + return false; + } + } + + // Check if y has extra properties + foreach (var key in yProps.Keys) + { + if (!xProps.ContainsKey(key)) + { + _failurePath = $"{path}: Unexpected property '{key}'"; + return false; + } + } + + // Compare each property value + foreach (var key in xProps.Keys) + { + var propPath = string.IsNullOrEmpty(path) ? key : $"{path}.{key}"; + if (!CompareJsonElements(xProps[key], yProps[key], propPath)) + { + return false; + } + } + + return true; + } + + private bool CompareJsonArraysInOrder(JsonElement x, JsonElement y, string path) + { + var xArray = x.EnumerateArray(); + var yArray = y.EnumerateArray(); + + // Count x elements + var xCount = 0; + var xElements = new List(); + foreach (var item in xArray) + { + xElements.Add(item); + xCount++; + } + + // Count y elements + var yCount = 0; + var yElements = new List(); + foreach (var item in yArray) + { + yElements.Add(item); + yCount++; + } + + // Check if counts match + if (xCount != yCount) + { + _failurePath = $"{path}: Expected {xCount} items but found {yCount}"; + return false; + } + + // Compare elements in order + for (var i = 0; i < xCount; i++) + { + var itemPath = $"{path}[{i}]"; + if (!CompareJsonElements(xElements[i], yElements[i], itemPath)) + { + return false; + } + } + + return true; + } + + /// + public override string ToString() + { + if (!string.IsNullOrEmpty(_failurePath)) + { + return $"JSON comparison failed at {_failurePath}"; + } + + return "JsonElementEqualityComparer"; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/NUnitExtensions.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/NUnitExtensions.cs new file mode 100644 index 000000000000..816f4c010e6e --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/NUnitExtensions.cs @@ -0,0 +1,32 @@ +using NUnit.Framework.Constraints; + +namespace NUnit.Framework; + +/// +/// Extensions for NUnit constraints. +/// +public static class NUnitExtensions +{ + /// + /// Modifies the EqualConstraint to use our own set of default comparers. + /// + /// + /// + public static EqualConstraint UsingDefaults(this EqualConstraint constraint) => + constraint + .UsingPropertiesComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingOneOfComparer() + .UsingJsonElementComparer() + .UsingOptionalComparer() + .UsingObjectDictionaryComparer() + .UsingAdditionalPropertiesComparer() + .UsingJsonSerializationComparer(); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/OneOfComparer.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/OneOfComparer.cs new file mode 100644 index 000000000000..5284755b7e9a --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/OneOfComparer.cs @@ -0,0 +1,100 @@ +using NUnit.Framework.Constraints; +using OneOf; +using SeedCsharpXmlEntities.Core; + +namespace NUnit.Framework; + +/// +/// Extensions for EqualConstraint to handle OneOf values. +/// +public static class EqualConstraintExtensions +{ + /// + /// Modifies the EqualConstraint to handle OneOf instances by comparing their inner values. + /// This works alongside other comparison modifiers like UsingPropertiesComparer. + /// + /// The EqualConstraint to modify. + /// The same constraint instance for method chaining. + public static EqualConstraint UsingOneOfComparer(this EqualConstraint constraint) + { + // Register a comparer factory for IOneOf types + constraint.Using( + (x, y) => + { + // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (x.Value is null && y.Value is null) + { + return true; + } + + if (x.Value is null) + { + return false; + } + + // Undiscriminated unions of string enums are only distinguishable by their + // wire value: the concrete member type is not recoverable when deserializing, + // so two members with the same string value are considered equal. + if (x.Value is IStringEnum xStringEnum && y.Value is IStringEnum yStringEnum) + { + return xStringEnum.Value == yStringEnum.Value; + } + + var propertiesComparer = new NUnitEqualityComparer(); + var tolerance = Tolerance.Default; + propertiesComparer.CompareProperties = true; + // Add OneOf comparer to handle nested OneOf values (e.g., in Lists) + propertiesComparer.ExternalComparers.Add( + new OneOfEqualityAdapter(propertiesComparer) + ); + return propertiesComparer.AreEqual(x.Value, y.Value, ref tolerance); + } + ); + + return constraint; + } + + /// + /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. + /// This enables recursive comparison of nested OneOf values. + /// + private class OneOfEqualityAdapter : EqualityAdapter + { + private readonly NUnitEqualityComparer _comparer; + + public OneOfEqualityAdapter(NUnitEqualityComparer comparer) + { + _comparer = comparer; + } + + public override bool CanCompare(object? x, object? y) + { + return x is IOneOf && y is IOneOf; + } + + public override bool AreEqual(object? x, object? y) + { + var oneOfX = (IOneOf?)x; + var oneOfY = (IOneOf?)y; + + // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (oneOfX?.Value is null && oneOfY?.Value is null) + { + return true; + } + + if (oneOfX?.Value is null || oneOfY?.Value is null) + { + return false; + } + + if (oneOfX.Value is IStringEnum xStringEnum && oneOfY.Value is IStringEnum yStringEnum) + { + return xStringEnum.Value == yStringEnum.Value; + } + + var tolerance = Tolerance.Default; + return _comparer.AreEqual(oneOfX.Value, oneOfY.Value, ref tolerance); + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/OptionalComparer.cs new file mode 100644 index 000000000000..3cd4bd8ae2f8 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/OptionalComparer.cs @@ -0,0 +1,104 @@ +using NUnit.Framework.Constraints; +using OneOf; +using SeedCsharpXmlEntities.Core; + +namespace NUnit.Framework; + +/// +/// Extensions for EqualConstraint to handle Optional values. +/// +public static class OptionalComparerExtensions +{ + /// + /// Modifies the EqualConstraint to handle Optional instances by comparing their IsDefined state and inner values. + /// This works alongside other comparison modifiers like UsingPropertiesComparer. + /// + /// The EqualConstraint to modify. + /// The same constraint instance for method chaining. + public static EqualConstraint UsingOptionalComparer(this EqualConstraint constraint) + { + // Register a comparer factory for IOptional types + constraint.Using( + (x, y) => + { + // Both must have the same IsDefined state + if (x.IsDefined != y.IsDefined) + { + return false; + } + + // If both are undefined, they're equal + if (!x.IsDefined) + { + return true; + } + + // Both are defined, compare their boxed values + var xValue = x.GetBoxedValue(); + var yValue = y.GetBoxedValue(); + + // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (xValue is null && yValue is null) + { + return true; + } + + if (xValue is null || yValue is null) + { + return false; + } + + // Use NUnit's property comparer for the inner values + var propertiesComparer = new NUnitEqualityComparer(); + var tolerance = Tolerance.Default; + propertiesComparer.CompareProperties = true; + // Add OneOf comparer to handle nested OneOf values (e.g., in Lists within Optional) + propertiesComparer.ExternalComparers.Add( + new OneOfEqualityAdapter(propertiesComparer) + ); + return propertiesComparer.AreEqual(xValue, yValue, ref tolerance); + } + ); + + return constraint; + } + + /// + /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. + /// + private class OneOfEqualityAdapter : EqualityAdapter + { + private readonly NUnitEqualityComparer _comparer; + + public OneOfEqualityAdapter(NUnitEqualityComparer comparer) + { + _comparer = comparer; + } + + public override bool CanCompare(object? x, object? y) + { + return x is IOneOf && y is IOneOf; + } + + public override bool AreEqual(object? x, object? y) + { + var oneOfX = (IOneOf?)x; + var oneOfY = (IOneOf?)y; + + // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (oneOfX?.Value is null && oneOfY?.Value is null) + { + return true; + } + + if (oneOfX?.Value is null || oneOfY?.Value is null) + { + return false; + } + + var tolerance = Tolerance.Default; + return _comparer.AreEqual(oneOfX.Value, oneOfY.Value, ref tolerance); + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/ReadOnlyMemoryComparer.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/ReadOnlyMemoryComparer.cs new file mode 100644 index 000000000000..fc0b595a5e54 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities.Test/Utils/ReadOnlyMemoryComparer.cs @@ -0,0 +1,87 @@ +using NUnit.Framework.Constraints; + +namespace NUnit.Framework; + +/// +/// Extensions for NUnit constraints. +/// +public static class ReadOnlyMemoryComparerExtensions +{ + /// + /// Extension method for comparing ReadOnlyMemory<T> in NUnit tests. + /// + /// The type of elements in the ReadOnlyMemory. + /// The Is.EqualTo() constraint instance. + /// A constraint that can compare ReadOnlyMemory<T>. + public static EqualConstraint UsingReadOnlyMemoryComparer(this EqualConstraint constraint) + where T : IComparable + { + return constraint.Using(new ReadOnlyMemoryComparer()); + } +} + +/// +/// Comparer for ReadOnlyMemory<T>. Compares sequences by value. +/// +/// +/// The type of elements in the ReadOnlyMemory. +/// +public class ReadOnlyMemoryComparer : IComparer> + where T : IComparable +{ + /// + public int Compare(ReadOnlyMemory x, ReadOnlyMemory y) + { + // Check if sequences are equal + var xSpan = x.Span; + var ySpan = y.Span; + + // Optimized case for IEquatable implementations + if (typeof(IEquatable).IsAssignableFrom(typeof(T))) + { + var areEqual = xSpan.SequenceEqual(ySpan); + if (areEqual) + { + return 0; // Sequences are equal + } + } + else + { + // Manual equality check for non-IEquatable types + if (xSpan.Length == ySpan.Length) + { + var areEqual = true; + for (var i = 0; i < xSpan.Length; i++) + { + if (!EqualityComparer.Default.Equals(xSpan[i], ySpan[i])) + { + areEqual = false; + break; + } + } + + if (areEqual) + { + return 0; // Sequences are equal + } + } + } + + // For non-equal sequences, we need to return a consistent ordering + // First compare lengths + if (x.Length != y.Length) + return x.Length.CompareTo(y.Length); + + // Same length but different content - compare first differing element + for (var i = 0; i < x.Length; i++) + { + if (!EqualityComparer.Default.Equals(xSpan[i], ySpan[i])) + { + return xSpan[i].CompareTo(ySpan[i]); + } + } + + // Should never reach here if not equal + return 0; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/ApiResponse.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/ApiResponse.cs new file mode 100644 index 000000000000..cd8bc2ebe8b6 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/ApiResponse.cs @@ -0,0 +1,13 @@ +using global::System.Net.Http; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// The response object returned from the API. +/// +internal record ApiResponse +{ + internal required int StatusCode { get; init; } + + internal required HttpResponseMessage Raw { get; init; } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/BaseRequest.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/BaseRequest.cs new file mode 100644 index 000000000000..caf83514a692 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/BaseRequest.cs @@ -0,0 +1,67 @@ +using global::System.Net.Http; +using global::System.Net.Http.Headers; +using global::System.Text; + +namespace SeedCsharpXmlEntities.Core; + +internal abstract record BaseRequest +{ + internal string? BaseUrl { get; init; } + + internal required HttpMethod Method { get; init; } + + internal required string Path { get; init; } + + internal string? ContentType { get; init; } + + /// + /// The query string for this request (including the leading '?' if non-empty). + /// + internal string? QueryString { get; init; } + + internal Dictionary Headers { get; init; } = + new(StringComparer.OrdinalIgnoreCase); + + internal IRequestOptions? Options { get; init; } + + internal abstract HttpContent? CreateContent(); + + protected static ( + Encoding encoding, + string? charset, + string mediaType + ) ParseContentTypeOrDefault( + string? contentType, + Encoding encodingFallback, + string mediaTypeFallback + ) + { + var encoding = encodingFallback; + var mediaType = mediaTypeFallback; + string? charset = null; + if (string.IsNullOrEmpty(contentType)) + { + return (encoding, charset, mediaType); + } + + if (!MediaTypeHeaderValue.TryParse(contentType, out var mediaTypeHeaderValue)) + { + return (encoding, charset, mediaType); + } + + if (!string.IsNullOrEmpty(mediaTypeHeaderValue.CharSet)) + { + charset = mediaTypeHeaderValue.CharSet; + encoding = Encoding.GetEncoding(mediaTypeHeaderValue.CharSet); + } + + if (!string.IsNullOrEmpty(mediaTypeHeaderValue.MediaType)) + { + mediaType = mediaTypeHeaderValue.MediaType; + } + + return (encoding, charset, mediaType); + } + + protected static Encoding Utf8NoBom => EncodingCache.Utf8NoBom; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/CollectionItemSerializer.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/CollectionItemSerializer.cs new file mode 100644 index 000000000000..ef7d24e58d75 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/CollectionItemSerializer.cs @@ -0,0 +1,91 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Json collection converter. +/// +/// Type of item to convert. +/// Converter to use for individual items. +internal class CollectionItemSerializer + : JsonConverter> + where TConverterType : JsonConverter, new() +{ + private static readonly TConverterType _converter = new TConverterType(); + + /// + /// Reads a json string and deserializes it into an object. + /// + /// Json reader. + /// Type to convert. + /// Serializer options. + /// Created object. + public override IEnumerable? Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType == JsonTokenType.Null) + { + return default; + } + + var jsonSerializerOptions = new JsonSerializerOptions(options); + jsonSerializerOptions.Converters.Clear(); + jsonSerializerOptions.Converters.Add(_converter); + + var returnValue = new List(); + + while (reader.TokenType != JsonTokenType.EndArray) + { + if (reader.TokenType != JsonTokenType.StartArray) + { + var item = (TDatatype)( + JsonSerializer.Deserialize(ref reader, typeof(TDatatype), jsonSerializerOptions) + ?? throw new global::System.Exception( + $"Failed to deserialize collection item of type {typeof(TDatatype)}" + ) + ); + returnValue.Add(item); + } + + reader.Read(); + } + + return returnValue; + } + + /// + /// Writes a json string. + /// + /// Json writer. + /// Value to write. + /// Serializer options. + public override void Write( + Utf8JsonWriter writer, + IEnumerable? value, + JsonSerializerOptions options + ) + { + if (value is null) + { + writer.WriteNullValue(); + return; + } + + var jsonSerializerOptions = new JsonSerializerOptions(options); + jsonSerializerOptions.Converters.Clear(); + jsonSerializerOptions.Converters.Add(_converter); + + writer.WriteStartArray(); + + foreach (var data in value) + { + JsonSerializer.Serialize(writer, data, jsonSerializerOptions); + } + + writer.WriteEndArray(); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Constants.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Constants.cs new file mode 100644 index 000000000000..79ccd1bff388 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Constants.cs @@ -0,0 +1,7 @@ +namespace SeedCsharpXmlEntities.Core; + +internal static class Constants +{ + public const string DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffK"; + public const string DateFormat = "yyyy-MM-dd"; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/DateOnlyConverter.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/DateOnlyConverter.cs new file mode 100644 index 000000000000..2a52421a4a45 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/DateOnlyConverter.cs @@ -0,0 +1,747 @@ +// ReSharper disable All +#pragma warning disable + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using global::System.Diagnostics; +using global::System.Diagnostics.CodeAnalysis; +using global::System.Globalization; +using global::System.Runtime.CompilerServices; +using global::System.Runtime.InteropServices; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +// ReSharper disable SuggestVarOrType_SimpleTypes +// ReSharper disable SuggestVarOrType_BuiltInTypes + +namespace SeedCsharpXmlEntities.Core +{ + /// + /// Custom converter for handling the data type with the System.Text.Json library. + /// + /// + /// This class backported from: + /// + /// System.Text.Json.Serialization.Converters.DateOnlyConverter + /// + public sealed class DateOnlyConverter : JsonConverter + { + private const int FormatLength = 10; // YYYY-MM-DD + + private const int MaxEscapedFormatLength = + FormatLength * JsonConstants.MaxExpansionFactorWhileEscaping; + + /// + public override DateOnly Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType != JsonTokenType.String) + { + ThrowHelper.ThrowInvalidOperationException_ExpectedString(reader.TokenType); + } + + return ReadCore(ref reader); + } + + /// + public override DateOnly ReadAsPropertyName( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); + return ReadCore(ref reader); + } + + private static DateOnly ReadCore(ref Utf8JsonReader reader) + { + if ( + !JsonHelpers.IsInRangeInclusive( + reader.ValueLength(), + FormatLength, + MaxEscapedFormatLength + ) + ) + { + ThrowHelper.ThrowFormatException(DataType.DateOnly); + } + + scoped ReadOnlySpan source; + if (!reader.HasValueSequence && !reader.ValueIsEscaped) + { + source = reader.ValueSpan; + } + else + { + Span stackSpan = stackalloc byte[MaxEscapedFormatLength]; + int bytesWritten = reader.CopyString(stackSpan); + source = stackSpan.Slice(0, bytesWritten); + } + + if (!JsonHelpers.TryParseAsIso(source, out DateOnly value)) + { + ThrowHelper.ThrowFormatException(DataType.DateOnly); + } + + return value; + } + + /// + public override void Write( + Utf8JsonWriter writer, + DateOnly value, + JsonSerializerOptions options + ) + { +#if NET8_0_OR_GREATER + Span buffer = stackalloc byte[FormatLength]; +#else + Span buffer = stackalloc char[FormatLength]; +#endif + // ReSharper disable once RedundantAssignment + bool formattedSuccessfully = value.TryFormat( + buffer, + out int charsWritten, + "O".AsSpan(), + CultureInfo.InvariantCulture + ); + Debug.Assert(formattedSuccessfully && charsWritten == FormatLength); + writer.WriteStringValue(buffer); + } + + /// + public override void WriteAsPropertyName( + Utf8JsonWriter writer, + DateOnly value, + JsonSerializerOptions options + ) + { +#if NET8_0_OR_GREATER + Span buffer = stackalloc byte[FormatLength]; +#else + Span buffer = stackalloc char[FormatLength]; +#endif + // ReSharper disable once RedundantAssignment + bool formattedSuccessfully = value.TryFormat( + buffer, + out int charsWritten, + "O".AsSpan(), + CultureInfo.InvariantCulture + ); + Debug.Assert(formattedSuccessfully && charsWritten == FormatLength); + writer.WritePropertyName(buffer); + } + } + + internal static class JsonConstants + { + // The maximum number of fraction digits the Json DateTime parser allows + public const int DateTimeParseNumFractionDigits = 16; + + // In the worst case, an ASCII character represented as a single utf-8 byte could expand 6x when escaped. + public const int MaxExpansionFactorWhileEscaping = 6; + + // The largest fraction expressible by TimeSpan and DateTime formats + public const int MaxDateTimeFraction = 9_999_999; + + // TimeSpan and DateTime formats allow exactly up to many digits for specifying the fraction after the seconds. + public const int DateTimeNumFractionDigits = 7; + + public const byte UtcOffsetToken = (byte)'Z'; + + public const byte TimePrefix = (byte)'T'; + + public const byte Period = (byte)'.'; + + public const byte Hyphen = (byte)'-'; + + public const byte Colon = (byte)':'; + + public const byte Plus = (byte)'+'; + } + + // ReSharper disable SuggestVarOrType_Elsewhere + // ReSharper disable SuggestVarOrType_SimpleTypes + // ReSharper disable SuggestVarOrType_BuiltInTypes + + internal static class JsonHelpers + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsInRangeInclusive(int value, int lowerBound, int upperBound) => + (uint)(value - lowerBound) <= (uint)(upperBound - lowerBound); + + public static bool IsDigit(byte value) => (uint)(value - '0') <= '9' - '0'; + + [StructLayout(LayoutKind.Auto)] + private struct DateTimeParseData + { + public int Year; + public int Month; + public int Day; + public bool IsCalendarDateOnly; + public int Hour; + public int Minute; + public int Second; + public int Fraction; // This value should never be greater than 9_999_999. + public int OffsetHours; + public int OffsetMinutes; + + // ReSharper disable once NotAccessedField.Local + public byte OffsetToken; + } + + public static bool TryParseAsIso(ReadOnlySpan source, out DateOnly value) + { + if ( + TryParseDateTimeOffset(source, out DateTimeParseData parseData) + && parseData.IsCalendarDateOnly + && TryCreateDateTime(parseData, DateTimeKind.Unspecified, out DateTime dateTime) + ) + { + value = DateOnly.FromDateTime(dateTime); + return true; + } + + value = default; + return false; + } + + /// + /// ISO 8601 date time parser (ISO 8601-1:2019). + /// + /// The date/time to parse in UTF-8 format. + /// The parsed for the given . + /// + /// Supports extended calendar date (5.2.2.1) and complete (5.4.2.1) calendar date/time of day + /// representations with optional specification of seconds and fractional seconds. + /// + /// Times can be explicitly specified as UTC ("Z" - 5.3.3) or offsets from UTC ("+/-hh:mm" 5.3.4.2). + /// If unspecified they are considered to be local per spec. + /// + /// Examples: (TZD is either "Z" or hh:mm offset from UTC) + /// + /// YYYY-MM-DD (e.g. 1997-07-16) + /// YYYY-MM-DDThh:mm (e.g. 1997-07-16T19:20) + /// YYYY-MM-DDThh:mm:ss (e.g. 1997-07-16T19:20:30) + /// YYYY-MM-DDThh:mm:ss.s (e.g. 1997-07-16T19:20:30.45) + /// YYYY-MM-DDThh:mmTZD (e.g. 1997-07-16T19:20+01:00) + /// YYYY-MM-DDThh:mm:ssTZD (e.g. 1997-07-16T19:20:3001:00) + /// YYYY-MM-DDThh:mm:ss.sTZD (e.g. 1997-07-16T19:20:30.45Z) + /// + /// Generally speaking we always require the "extended" option when one exists (3.1.3.5). + /// The extended variants have separator characters between components ('-', ':', '.', etc.). + /// Spaces are not permitted. + /// + /// "true" if successfully parsed. + private static bool TryParseDateTimeOffset( + ReadOnlySpan source, + out DateTimeParseData parseData + ) + { + parseData = default; + + // too short datetime + Debug.Assert(source.Length >= 10); + + // Parse the calendar date + // ----------------------- + // ISO 8601-1:2019 5.2.2.1b "Calendar date complete extended format" + // [dateX] = [year]["-"][month]["-"][day] + // [year] = [YYYY] [0000 - 9999] (4.3.2) + // [month] = [MM] [01 - 12] (4.3.3) + // [day] = [DD] [01 - 28, 29, 30, 31] (4.3.4) + // + // Note: 5.2.2.2 "Representations with reduced precision" allows for + // just [year]["-"][month] (a) and just [year] (b), but we currently + // don't permit it. + + { + uint digit1 = source[0] - (uint)'0'; + uint digit2 = source[1] - (uint)'0'; + uint digit3 = source[2] - (uint)'0'; + uint digit4 = source[3] - (uint)'0'; + + if (digit1 > 9 || digit2 > 9 || digit3 > 9 || digit4 > 9) + { + return false; + } + + parseData.Year = (int)(digit1 * 1000 + digit2 * 100 + digit3 * 10 + digit4); + } + + if ( + source[4] != JsonConstants.Hyphen + || !TryGetNextTwoDigits(source.Slice(start: 5, length: 2), ref parseData.Month) + || source[7] != JsonConstants.Hyphen + || !TryGetNextTwoDigits(source.Slice(start: 8, length: 2), ref parseData.Day) + ) + { + return false; + } + + // We now have YYYY-MM-DD [dateX] + // ReSharper disable once ConvertIfStatementToSwitchStatement + if (source.Length == 10) + { + parseData.IsCalendarDateOnly = true; + return true; + } + + // Parse the time of day + // --------------------- + // + // ISO 8601-1:2019 5.3.1.2b "Local time of day complete extended format" + // [timeX] = ["T"][hour][":"][min][":"][sec] + // [hour] = [hh] [00 - 23] (4.3.8a) + // [minute] = [mm] [00 - 59] (4.3.9a) + // [sec] = [ss] [00 - 59, 60 with a leap second] (4.3.10a) + // + // ISO 8601-1:2019 5.3.3 "UTC of day" + // [timeX]["Z"] + // + // ISO 8601-1:2019 5.3.4.2 "Local time of day with the time shift between + // local timescale and UTC" (Extended format) + // + // [shiftX] = ["+"|"-"][hour][":"][min] + // + // Notes: + // + // "T" is optional per spec, but _only_ when times are used alone. In our + // case, we're reading out a complete date & time and as such require "T". + // (5.4.2.1b). + // + // For [timeX] We allow seconds to be omitted per 5.3.1.3a "Representations + // with reduced precision". 5.3.1.3b allows just specifying the hour, but + // we currently don't permit this. + // + // Decimal fractions are allowed for hours, minutes and seconds (5.3.14). + // We only allow fractions for seconds currently. Lower order components + // can't follow, i.e. you can have T23.3, but not T23.3:04. There must be + // one digit, but the max number of digits is implementation defined. We + // currently allow up to 16 digits of fractional seconds only. While we + // support 16 fractional digits we only parse the first seven, anything + // past that is considered a zero. This is to stay compatible with the + // DateTime implementation which is limited to this resolution. + + if (source.Length < 16) + { + // Source does not have enough characters for YYYY-MM-DDThh:mm + return false; + } + + // Parse THH:MM (e.g. "T10:32") + if ( + source[10] != JsonConstants.TimePrefix + || source[13] != JsonConstants.Colon + || !TryGetNextTwoDigits(source.Slice(start: 11, length: 2), ref parseData.Hour) + || !TryGetNextTwoDigits(source.Slice(start: 14, length: 2), ref parseData.Minute) + ) + { + return false; + } + + // We now have YYYY-MM-DDThh:mm + Debug.Assert(source.Length >= 16); + if (source.Length == 16) + { + return true; + } + + byte curByte = source[16]; + int sourceIndex = 17; + + // Either a TZD ['Z'|'+'|'-'] or a seconds separator [':'] is valid at this point + switch (curByte) + { + case JsonConstants.UtcOffsetToken: + parseData.OffsetToken = JsonConstants.UtcOffsetToken; + return sourceIndex == source.Length; + case JsonConstants.Plus: + case JsonConstants.Hyphen: + parseData.OffsetToken = curByte; + return ParseOffset(ref parseData, source.Slice(sourceIndex)); + case JsonConstants.Colon: + break; + default: + return false; + } + + // Try reading the seconds + if ( + source.Length < 19 + || !TryGetNextTwoDigits(source.Slice(start: 17, length: 2), ref parseData.Second) + ) + { + return false; + } + + // We now have YYYY-MM-DDThh:mm:ss + Debug.Assert(source.Length >= 19); + if (source.Length == 19) + { + return true; + } + + curByte = source[19]; + sourceIndex = 20; + + // Either a TZD ['Z'|'+'|'-'] or a seconds decimal fraction separator ['.'] is valid at this point + switch (curByte) + { + case JsonConstants.UtcOffsetToken: + parseData.OffsetToken = JsonConstants.UtcOffsetToken; + return sourceIndex == source.Length; + case JsonConstants.Plus: + case JsonConstants.Hyphen: + parseData.OffsetToken = curByte; + return ParseOffset(ref parseData, source.Slice(sourceIndex)); + case JsonConstants.Period: + break; + default: + return false; + } + + // Source does not have enough characters for second fractions (i.e. ".s") + // YYYY-MM-DDThh:mm:ss.s + if (source.Length < 21) + { + return false; + } + + // Parse fraction. This value should never be greater than 9_999_999 + int numDigitsRead = 0; + int fractionEnd = Math.Min( + sourceIndex + JsonConstants.DateTimeParseNumFractionDigits, + source.Length + ); + + while (sourceIndex < fractionEnd && IsDigit(curByte = source[sourceIndex])) + { + if (numDigitsRead < JsonConstants.DateTimeNumFractionDigits) + { + parseData.Fraction = parseData.Fraction * 10 + (int)(curByte - (uint)'0'); + numDigitsRead++; + } + + sourceIndex++; + } + + if (parseData.Fraction != 0) + { + while (numDigitsRead < JsonConstants.DateTimeNumFractionDigits) + { + parseData.Fraction *= 10; + numDigitsRead++; + } + } + + // We now have YYYY-MM-DDThh:mm:ss.s + Debug.Assert(sourceIndex <= source.Length); + if (sourceIndex == source.Length) + { + return true; + } + + curByte = source[sourceIndex++]; + + // TZD ['Z'|'+'|'-'] is valid at this point + switch (curByte) + { + case JsonConstants.UtcOffsetToken: + parseData.OffsetToken = JsonConstants.UtcOffsetToken; + return sourceIndex == source.Length; + case JsonConstants.Plus: + case JsonConstants.Hyphen: + parseData.OffsetToken = curByte; + return ParseOffset(ref parseData, source.Slice(sourceIndex)); + default: + return false; + } + + static bool ParseOffset(ref DateTimeParseData parseData, ReadOnlySpan offsetData) + { + // Parse the hours for the offset + if ( + offsetData.Length < 2 + || !TryGetNextTwoDigits(offsetData.Slice(0, 2), ref parseData.OffsetHours) + ) + { + return false; + } + + // We now have YYYY-MM-DDThh:mm:ss.s+|-hh + + if (offsetData.Length == 2) + { + // Just hours offset specified + return true; + } + + // Ensure we have enough for ":mm" + return offsetData.Length == 5 + && offsetData[2] == JsonConstants.Colon + && TryGetNextTwoDigits(offsetData.Slice(3), ref parseData.OffsetMinutes); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + // ReSharper disable once RedundantAssignment + private static bool TryGetNextTwoDigits(ReadOnlySpan source, ref int value) + { + Debug.Assert(source.Length == 2); + + uint digit1 = source[0] - (uint)'0'; + uint digit2 = source[1] - (uint)'0'; + + if (digit1 > 9 || digit2 > 9) + { + value = 0; + return false; + } + + value = (int)(digit1 * 10 + digit2); + return true; + } + + // The following methods are borrowed verbatim from src/Common/src/CoreLib/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.Helpers.cs + + /// + /// Overflow-safe DateTime factory. + /// + private static bool TryCreateDateTime( + DateTimeParseData parseData, + DateTimeKind kind, + out DateTime value + ) + { + if (parseData.Year == 0) + { + value = default; + return false; + } + + Debug.Assert(parseData.Year <= 9999); // All of our callers to date parse the year from fixed 4-digit fields so this value is trusted. + + if ((uint)parseData.Month - 1 >= 12) + { + value = default; + return false; + } + + uint dayMinusOne = (uint)parseData.Day - 1; + if ( + dayMinusOne >= 28 + && dayMinusOne >= DateTime.DaysInMonth(parseData.Year, parseData.Month) + ) + { + value = default; + return false; + } + + if ((uint)parseData.Hour > 23) + { + value = default; + return false; + } + + if ((uint)parseData.Minute > 59) + { + value = default; + return false; + } + + // This needs to allow leap seconds when appropriate. + // See https://github.com/dotnet/runtime/issues/30135. + if ((uint)parseData.Second > 59) + { + value = default; + return false; + } + + Debug.Assert(parseData.Fraction is >= 0 and <= JsonConstants.MaxDateTimeFraction); // All of our callers to date parse the fraction from fixed 7-digit fields so this value is trusted. + + ReadOnlySpan days = DateTime.IsLeapYear(parseData.Year) + ? DaysToMonth366 + : DaysToMonth365; + int yearMinusOne = parseData.Year - 1; + int totalDays = + yearMinusOne * 365 + + yearMinusOne / 4 + - yearMinusOne / 100 + + yearMinusOne / 400 + + days[parseData.Month - 1] + + parseData.Day + - 1; + long ticks = totalDays * TimeSpan.TicksPerDay; + int totalSeconds = parseData.Hour * 3600 + parseData.Minute * 60 + parseData.Second; + ticks += totalSeconds * TimeSpan.TicksPerSecond; + ticks += parseData.Fraction; + value = new DateTime(ticks: ticks, kind: kind); + return true; + } + + private static ReadOnlySpan DaysToMonth365 => + [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; + private static ReadOnlySpan DaysToMonth366 => + [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]; + } + + internal static class ThrowHelper + { + private const string ExceptionSourceValueToRethrowAsJsonException = + "System.Text.Json.Rethrowable"; + + [DoesNotReturn] + public static void ThrowInvalidOperationException_ExpectedString(JsonTokenType tokenType) + { + throw GetInvalidOperationException("string", tokenType); + } + + public static void ThrowFormatException(DataType dataType) + { + throw new FormatException(SR.Format(SR.UnsupportedFormat, dataType)) + { + Source = ExceptionSourceValueToRethrowAsJsonException, + }; + } + + private static global::System.Exception GetInvalidOperationException( + string message, + JsonTokenType tokenType + ) + { + return GetInvalidOperationException(SR.Format(SR.InvalidCast, tokenType, message)); + } + + private static InvalidOperationException GetInvalidOperationException(string message) + { + return new InvalidOperationException(message) + { + Source = ExceptionSourceValueToRethrowAsJsonException, + }; + } + } + + internal static class Utf8JsonReaderExtensions + { + internal static int ValueLength(this Utf8JsonReader reader) => + reader.HasValueSequence + ? checked((int)reader.ValueSequence.Length) + : reader.ValueSpan.Length; + } + + internal enum DataType + { + TimeOnly, + DateOnly, + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + internal static class SR + { + private static readonly bool s_usingResourceKeys = + AppContext.TryGetSwitch( + "System.Resources.UseSystemResourceKeys", + out bool usingResourceKeys + ) && usingResourceKeys; + + public static string UnsupportedFormat => Strings.UnsupportedFormat; + + public static string InvalidCast => Strings.InvalidCast; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static string Format(string resourceFormat, object? p1) => + s_usingResourceKeys + ? string.Join(", ", resourceFormat, p1) + : string.Format(resourceFormat, p1); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static string Format(string resourceFormat, object? p1, object? p2) => + s_usingResourceKeys + ? string.Join(", ", resourceFormat, p1, p2) + : string.Format(resourceFormat, p1, p2); + } + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute( + "System.Resources.Tools.StronglyTypedResourceBuilder", + "17.0.0.0" + )] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Strings + { + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute( + "Microsoft.Performance", + "CA1811:AvoidUncalledPrivateCode" + )] + internal Strings() { } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute( + global::System.ComponentModel.EditorBrowsableState.Advanced + )] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if (object.ReferenceEquals(resourceMan, null)) + { + global::System.Resources.ResourceManager temp = + new global::System.Resources.ResourceManager( + "System.Text.Json.Resources.Strings", + typeof(Strings).Assembly + ); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute( + global::System.ComponentModel.EditorBrowsableState.Advanced + )] + internal static global::System.Globalization.CultureInfo Culture + { + get { return resourceCulture; } + set { resourceCulture = value; } + } + + /// + /// Looks up a localized string similar to Cannot get the value of a token type '{0}' as a {1}.. + /// + internal static string InvalidCast + { + get { return ResourceManager.GetString("InvalidCast", resourceCulture); } + } + + /// + /// Looks up a localized string similar to The JSON value is not in a supported {0} format.. + /// + internal static string UnsupportedFormat + { + get { return ResourceManager.GetString("UnsupportedFormat", resourceCulture); } + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/DateTimeSerializer.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/DateTimeSerializer.cs new file mode 100644 index 000000000000..d2cdcefbbcfb --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/DateTimeSerializer.cs @@ -0,0 +1,40 @@ +using global::System.Globalization; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace SeedCsharpXmlEntities.Core; + +internal class DateTimeSerializer : JsonConverter +{ + public override DateTime Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + return DateTime.Parse(reader.GetString()!, null, DateTimeStyles.RoundtripKind); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString(Constants.DateTimeFormat)); + } + + public override DateTime ReadAsPropertyName( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + return DateTime.Parse(reader.GetString()!, null, DateTimeStyles.RoundtripKind); + } + + public override void WriteAsPropertyName( + Utf8JsonWriter writer, + DateTime value, + JsonSerializerOptions options + ) + { + writer.WritePropertyName(value.ToString(Constants.DateTimeFormat)); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/DefaultHttpClientFactory.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/DefaultHttpClientFactory.cs new file mode 100644 index 000000000000..f77fc76be50b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/DefaultHttpClientFactory.cs @@ -0,0 +1,25 @@ +using global::System.Net; +using global::System.Net.Http; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Creates the default used by the SDK, with automatic +/// response decompression enabled so that gzip/deflate encoded response bodies +/// are decompressed based on the response's Content-Encoding header. +/// +internal static class DefaultHttpClientFactory +{ + internal static HttpClient Create() + { + var handler = new HttpClientHandler + { +#if NET5_0_OR_GREATER + AutomaticDecompression = DecompressionMethods.All, +#else + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, +#endif + }; + return new HttpClient(handler); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/EmptyRequest.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/EmptyRequest.cs new file mode 100644 index 000000000000..4a2f72c48de4 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/EmptyRequest.cs @@ -0,0 +1,11 @@ +using global::System.Net.Http; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// The request object to send without a request body. +/// +internal record EmptyRequest : BaseRequest +{ + internal override HttpContent? CreateContent() => null; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/EncodingCache.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/EncodingCache.cs new file mode 100644 index 000000000000..91020ab27a68 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/EncodingCache.cs @@ -0,0 +1,11 @@ +using global::System.Text; + +namespace SeedCsharpXmlEntities.Core; + +internal static class EncodingCache +{ + internal static readonly Encoding Utf8NoBom = new UTF8Encoding( + encoderShouldEmitUTF8Identifier: false, + throwOnInvalidBytes: true + ); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Extensions.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Extensions.cs new file mode 100644 index 000000000000..dba70c9670ae --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Extensions.cs @@ -0,0 +1,57 @@ +using global::System.Diagnostics.CodeAnalysis; +using global::System.Runtime.Serialization; + +namespace SeedCsharpXmlEntities.Core; + +internal static class Extensions +{ + public static string Stringify(this Enum value) + { + var field = value.GetType().GetField(value.ToString()); + if (field is not null) + { + var attribute = (EnumMemberAttribute?) + global::System.Attribute.GetCustomAttribute(field, typeof(EnumMemberAttribute)); + return attribute?.Value ?? value.ToString(); + } + return value.ToString(); + } + + /// + /// Asserts that a condition is true, throwing an exception with the specified message if it is false. + /// + /// The object the extension method is invoked on; unused. + /// The condition to assert. + /// The exception message if the assertion fails. + /// Thrown when the condition is false. + internal static void Assert(this object value, bool condition, string message) + { + if (!condition) + { + throw new global::System.Exception(message); + } + } + + /// + /// Asserts that a value is not null, throwing an exception with the specified message if it is null. + /// + /// The type of the value to assert. + /// The object the extension method is invoked on; unused. + /// The value to assert is not null. + /// The exception message if the assertion fails. + /// The non-null value. + /// Thrown when the value is null. + internal static TValue Assert( + this object _unused, + [NotNull] TValue? value, + string message + ) + where TValue : class + { + if (value is null) + { + throw new global::System.Exception(message); + } + return value; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/FormUrlEncoder.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/FormUrlEncoder.cs new file mode 100644 index 000000000000..679968707a8f --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/FormUrlEncoder.cs @@ -0,0 +1,33 @@ +using global::System.Net.Http; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Encodes an object into a form URL-encoded content. +/// +public static class FormUrlEncoder +{ + /// + /// Encodes an object into a form URL-encoded content using Deep Object notation. + /// + /// Object to form URL-encode. You can pass in an object or dictionary, but not lists, strings, or primitives. + /// Throws when passing in a list, a string, or a primitive value. + internal static FormUrlEncodedContent EncodeAsDeepObject(object value) => + new(QueryStringConverter.ToDeepObject(value)); + + /// + /// Encodes an object into a form URL-encoded content using Exploded Form notation. + /// + /// Object to form URL-encode. You can pass in an object or dictionary, but not lists, strings, or primitives. + /// Throws when passing in a list, a string, or a primitive value. + internal static FormUrlEncodedContent EncodeAsExplodedForm(object value) => + new(QueryStringConverter.ToExplodedForm(value)); + + /// + /// Encodes an object into a form URL-encoded content using Form notation without exploding parameters. + /// + /// Object to form URL-encode. You can pass in an object or dictionary, but not lists, strings, or primitives. + /// Throws when passing in a list, a string, or a primitive value. + internal static FormUrlEncodedContent EncodeAsForm(object value) => + new(QueryStringConverter.ToForm(value)); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HeaderValue.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HeaderValue.cs new file mode 100644 index 000000000000..59f4e01adcd9 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HeaderValue.cs @@ -0,0 +1,52 @@ +namespace SeedCsharpXmlEntities.Core; + +internal sealed class HeaderValue +{ + private readonly Func> _resolver; + + public HeaderValue(string value) + { + _resolver = () => new global::System.Threading.Tasks.ValueTask(value); + } + + public HeaderValue(Func value) + { + _resolver = () => new global::System.Threading.Tasks.ValueTask(value()); + } + + public HeaderValue(Func> value) + { + _resolver = value; + } + + public HeaderValue(Func> value) + { + _resolver = () => new global::System.Threading.Tasks.ValueTask(value()); + } + + public static implicit operator HeaderValue(string value) => new(value); + + public static implicit operator HeaderValue(Func value) => new(value); + + public static implicit operator HeaderValue( + Func> value + ) => new(value); + + public static implicit operator HeaderValue( + Func> value + ) => new(value); + + public static HeaderValue FromString(string value) => new(value); + + public static HeaderValue FromFunc(Func value) => new(value); + + public static HeaderValue FromValueTaskFunc( + Func> value + ) => new(value); + + public static HeaderValue FromTaskFunc( + Func> value + ) => new(value); + + internal global::System.Threading.Tasks.ValueTask ResolveAsync() => _resolver(); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Headers.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Headers.cs new file mode 100644 index 000000000000..17f7dd4517a6 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Headers.cs @@ -0,0 +1,28 @@ +namespace SeedCsharpXmlEntities.Core; + +/// +/// Represents the headers sent with the request. +/// +internal sealed class Headers : Dictionary +{ + internal Headers() { } + + /// + /// Initializes a new instance of the Headers class with the specified value. + /// + /// + internal Headers(Dictionary value) + { + foreach (var kvp in value) + { + this[kvp.Key] = kvp.Value; + } + } + + /// + /// Initializes a new instance of the Headers class with the specified value. + /// + /// + internal Headers(IEnumerable> value) + : base(value.ToDictionary(e => e.Key, e => e.Value)) { } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HeadersBuilder.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HeadersBuilder.cs new file mode 100644 index 000000000000..4893ea05b4c4 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HeadersBuilder.cs @@ -0,0 +1,197 @@ +namespace SeedCsharpXmlEntities.Core; + +/// +/// Fluent builder for constructing HTTP headers with support for merging from multiple sources. +/// Provides a clean API for building headers with proper precedence handling. +/// +internal static class HeadersBuilder +{ + /// + /// Fluent builder for constructing HTTP headers. + /// + public sealed class Builder + { + private readonly Dictionary _headers; + + /// + /// Initializes a new instance with default capacity. + /// Uses case-insensitive header name comparison. + /// + public Builder() + { + _headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + /// + /// Initializes a new instance with the specified initial capacity. + /// Uses case-insensitive header name comparison. + /// + public Builder(int capacity) + { + _headers = new Dictionary( + capacity, + StringComparer.OrdinalIgnoreCase + ); + } + + /// + /// Adds a header with the specified key and value. + /// If a header with the same key already exists, it will be overwritten. + /// Null values are ignored. + /// + /// The header name. + /// The header value. Null values are ignored. + /// This builder instance for method chaining. + public Builder Add(string key, string? value) + { + if (value is not null) + { + _headers[key] = (value); + } + return this; + } + + /// + /// Adds a header with the specified key and object value. + /// The value will be converted to string using ValueConvert for consistent serialization. + /// If a header with the same key already exists, it will be overwritten. + /// Null values are ignored. + /// + /// The header name. + /// The header value. Null values are ignored. + /// This builder instance for method chaining. + public Builder Add(string key, object? value) + { + if (value is null) + { + return this; + } + + // Use ValueConvert for consistent serialization across headers, query params, and path params + var stringValue = ValueConvert.ToString(value); + if (stringValue is not null) + { + _headers[key] = (stringValue); + } + return this; + } + + /// + /// Adds multiple headers from a Headers dictionary. + /// HeaderValue instances are stored and will be resolved when BuildAsync() is called. + /// Overwrites any existing headers with the same key. + /// Null entries are ignored. + /// + /// The headers to add. Null is treated as empty. + /// This builder instance for method chaining. + public Builder Add(Headers? headers) + { + if (headers is null) + { + return this; + } + + foreach (var header in headers) + { + _headers[header.Key] = header.Value; + } + + return this; + } + + /// + /// Adds multiple headers from a Headers dictionary, excluding the Authorization header. + /// This is useful for endpoints that don't require authentication, to avoid triggering + /// lazy auth token resolution. + /// HeaderValue instances are stored and will be resolved when BuildAsync() is called. + /// Overwrites any existing headers with the same key. + /// Null entries are ignored. + /// + /// The headers to add. Null is treated as empty. + /// This builder instance for method chaining. + public Builder AddWithoutAuth(Headers? headers) + { + if (headers is null) + { + return this; + } + + foreach (var header in headers) + { + if (header.Key.Equals("Authorization", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + _headers[header.Key] = header.Value; + } + + return this; + } + + /// + /// Adds multiple headers from a key-value pair collection. + /// Overwrites any existing headers with the same key. + /// Null values are ignored. + /// + /// The headers to add. Null is treated as empty. + /// This builder instance for method chaining. + public Builder Add(IEnumerable>? headers) + { + if (headers is null) + { + return this; + } + + foreach (var header in headers) + { + if (header.Value is not null) + { + _headers[header.Key] = (header.Value); + } + } + + return this; + } + + /// + /// Adds multiple headers from a dictionary. + /// Overwrites any existing headers with the same key. + /// + /// The headers to add. Null is treated as empty. + /// This builder instance for method chaining. + public Builder Add(Dictionary? headers) + { + if (headers is null) + { + return this; + } + + foreach (var header in headers) + { + _headers[header.Key] = (header.Value); + } + + return this; + } + + /// + /// Asynchronously builds the final headers dictionary containing all merged headers. + /// Resolves all HeaderValue instances that may contain async operations. + /// Returns a case-insensitive dictionary. + /// + /// A task that represents the asynchronous operation, containing a case-insensitive dictionary of headers. + public async global::System.Threading.Tasks.Task> BuildAsync() + { + var headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var kvp in _headers) + { + var value = await kvp.Value.ResolveAsync().ConfigureAwait(false); + if (value is not null) + { + headers[kvp.Key] = value; + } + } + return headers; + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HttpContentExtensions.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HttpContentExtensions.cs new file mode 100644 index 000000000000..b277051bd81d --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HttpContentExtensions.cs @@ -0,0 +1,20 @@ +#if !NET5_0_OR_GREATER +namespace SeedCsharpXmlEntities.Core; + +/// +/// Polyfill extension providing a ReadAsStringAsync(CancellationToken) overload +/// for target frameworks older than .NET 5, where only the parameterless +/// ReadAsStringAsync() is available. +/// +internal static class HttpContentExtensions +{ + internal static Task ReadAsStringAsync( + this HttpContent httpContent, + CancellationToken cancellationToken + ) + { + cancellationToken.ThrowIfCancellationRequested(); + return httpContent.ReadAsStringAsync(); + } +} +#endif diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HttpMethodExtensions.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HttpMethodExtensions.cs new file mode 100644 index 000000000000..09ebd779bde7 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/HttpMethodExtensions.cs @@ -0,0 +1,8 @@ +using global::System.Net.Http; + +namespace SeedCsharpXmlEntities.Core; + +internal static class HttpMethodExtensions +{ + public static readonly HttpMethod Patch = new("PATCH"); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/IIsRetryableContent.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/IIsRetryableContent.cs new file mode 100644 index 000000000000..1c3fc7b5e1c2 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/IIsRetryableContent.cs @@ -0,0 +1,6 @@ +namespace SeedCsharpXmlEntities.Core; + +public interface IIsRetryableContent +{ + public bool IsRetryable { get; } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/IRequestOptions.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/IRequestOptions.cs new file mode 100644 index 000000000000..0f818aa724cb --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/IRequestOptions.cs @@ -0,0 +1,83 @@ +namespace SeedCsharpXmlEntities.Core; + +internal interface IRequestOptions +{ + /// + /// The Base URL for the API. + /// + public string? BaseUrl { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// The http client used to make requests. + /// + public HttpClient? HttpClient { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// Additional headers to be sent with the request. + /// Headers previously set with matching keys will be overwritten. + /// + public IEnumerable> AdditionalHeaders { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// The max number of retries to attempt. + /// + public int? MaxRetries { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// The timeout for the request. + /// + public TimeSpan? Timeout { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// Additional query parameters sent with the request. + /// + public IEnumerable> AdditionalQueryParameters { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// Additional body properties sent with the request. + /// This is only applied to JSON requests. + /// + public object? AdditionalBodyProperties { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/JsonAccessAttribute.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/JsonAccessAttribute.cs new file mode 100644 index 000000000000..c2e49dc5d92b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/JsonAccessAttribute.cs @@ -0,0 +1,15 @@ +namespace SeedCsharpXmlEntities.Core; + +[global::System.AttributeUsage( + global::System.AttributeTargets.Property | global::System.AttributeTargets.Field +)] +internal class JsonAccessAttribute(JsonAccessType accessType) : global::System.Attribute +{ + internal JsonAccessType AccessType { get; init; } = accessType; +} + +internal enum JsonAccessType +{ + ReadOnly, + WriteOnly, +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/JsonConfiguration.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/JsonConfiguration.cs new file mode 100644 index 000000000000..684697dcceca --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/JsonConfiguration.cs @@ -0,0 +1,275 @@ +using global::System.Reflection; +using global::System.Text.Encodings.Web; +using global::System.Text.Json; +using global::System.Text.Json.Nodes; +using global::System.Text.Json.Serialization; +using global::System.Text.Json.Serialization.Metadata; + +namespace SeedCsharpXmlEntities.Core; + +internal static partial class JsonOptions +{ + internal static readonly JsonSerializerOptions JsonSerializerOptions; + internal static readonly JsonSerializerOptions JsonSerializerOptionsRelaxedEscaping; + + static JsonOptions() + { + var options = new JsonSerializerOptions + { + Converters = + { + new DateTimeSerializer(), +#if USE_PORTABLE_DATE_ONLY + new DateOnlyConverter(), +#endif + new OneOfSerializer(), + new OptionalJsonConverterFactory(), + }, +#if DEBUG + WriteIndented = true, +#endif + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + TypeInfoResolver = new DefaultJsonTypeInfoResolver + { + Modifiers = + { + NullableOptionalModifier, + JsonAccessAndIgnoreModifier, + HandleExtensionDataFields, + }, + }, + }; + ConfigureJsonSerializerOptions(options); + JsonSerializerOptions = options; + + var relaxedOptions = new JsonSerializerOptions(options) + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + }; + JsonSerializerOptionsRelaxedEscaping = relaxedOptions; + } + + private static void NullableOptionalModifier(JsonTypeInfo typeInfo) + { + if (typeInfo.Kind != JsonTypeInfoKind.Object) + return; + + foreach (var property in typeInfo.Properties) + { + var propertyInfo = property.AttributeProvider as global::System.Reflection.PropertyInfo; + + if (propertyInfo is null) + continue; + + // Check for ReadOnly JsonAccessAttribute - it overrides Optional/Nullable behavior + var jsonAccessAttribute = propertyInfo.GetCustomAttribute(); + if (jsonAccessAttribute?.AccessType == JsonAccessType.ReadOnly) + { + // ReadOnly means "never serialize", which completely overrides Optional/Nullable. + // Skip Optional/Nullable processing since JsonAccessAndIgnoreModifier + // will set ShouldSerialize = false anyway. + continue; + } + // Note: WriteOnly doesn't conflict with Optional/Nullable since it only + // affects deserialization (Set), not serialization (ShouldSerialize) + + var isOptionalType = + property.PropertyType.IsGenericType + && property.PropertyType.GetGenericTypeDefinition() == typeof(Optional<>); + + var hasOptionalAttribute = + propertyInfo.GetCustomAttribute() is not null; + var hasNullableAttribute = + propertyInfo.GetCustomAttribute() is not null; + + if (isOptionalType && hasOptionalAttribute) + { + var originalGetter = property.Get; + if (originalGetter is not null) + { + var capturedIsNullable = hasNullableAttribute; + + property.ShouldSerialize = (obj, value) => + { + var optionalValue = originalGetter(obj); + if (optionalValue is not IOptional optional) + return false; + + if (!optional.IsDefined) + return false; + + if (!capturedIsNullable) + { + var innerValue = optional.GetBoxedValue(); + if (innerValue is null) + return false; + } + + return true; + }; + } + } + else if (hasNullableAttribute) + { + // Force serialization of nullable properties even when null + property.ShouldSerialize = (obj, value) => true; + } + } + } + + private static void JsonAccessAndIgnoreModifier(JsonTypeInfo typeInfo) + { + if (typeInfo.Kind != JsonTypeInfoKind.Object) + return; + + foreach (var propertyInfo in typeInfo.Properties) + { + var jsonAccessAttribute = propertyInfo + .AttributeProvider?.GetCustomAttributes(typeof(JsonAccessAttribute), true) + .OfType() + .FirstOrDefault(); + + if (jsonAccessAttribute is not null) + { + propertyInfo.IsRequired = false; + switch (jsonAccessAttribute.AccessType) + { + case JsonAccessType.ReadOnly: + propertyInfo.ShouldSerialize = (_, _) => false; + break; + case JsonAccessType.WriteOnly: + propertyInfo.Set = null; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + var jsonIgnoreAttribute = propertyInfo + .AttributeProvider?.GetCustomAttributes(typeof(JsonIgnoreAttribute), true) + .OfType() + .FirstOrDefault(); + + if (jsonIgnoreAttribute is not null) + { + propertyInfo.IsRequired = false; + } + } + } + + private static void HandleExtensionDataFields(JsonTypeInfo typeInfo) + { + if ( + typeInfo.Kind == JsonTypeInfoKind.Object + && typeInfo.Properties.All(prop => !prop.IsExtensionData) + ) + { + var extensionProp = typeInfo + .Type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic) + .FirstOrDefault(prop => + prop.GetCustomAttribute() is not null + ); + + if (extensionProp is not null) + { + var jsonPropertyInfo = typeInfo.CreateJsonPropertyInfo( + extensionProp.FieldType, + extensionProp.Name + ); + jsonPropertyInfo.Get = extensionProp.GetValue; + jsonPropertyInfo.Set = extensionProp.SetValue; + jsonPropertyInfo.IsExtensionData = true; + typeInfo.Properties.Add(jsonPropertyInfo); + } + } + } + + static partial void ConfigureJsonSerializerOptions(JsonSerializerOptions defaultOptions); +} + +internal static class JsonUtils +{ + internal static string Serialize(T obj) => + JsonSerializer.Serialize(obj, JsonOptions.JsonSerializerOptions); + + internal static string Serialize(object obj, global::System.Type type) => + JsonSerializer.Serialize(obj, type, JsonOptions.JsonSerializerOptions); + + internal static string SerializeRelaxedEscaping(T obj) => + JsonSerializer.Serialize(obj, JsonOptions.JsonSerializerOptionsRelaxedEscaping); + + internal static string SerializeRelaxedEscaping(object obj, global::System.Type type) => + JsonSerializer.Serialize(obj, type, JsonOptions.JsonSerializerOptionsRelaxedEscaping); + + internal static JsonElement SerializeToElement(T obj) => + JsonSerializer.SerializeToElement(obj, JsonOptions.JsonSerializerOptions); + + internal static JsonElement SerializeToElement(object obj, global::System.Type type) => + JsonSerializer.SerializeToElement(obj, type, JsonOptions.JsonSerializerOptions); + + internal static JsonDocument SerializeToDocument(T obj) => + JsonSerializer.SerializeToDocument(obj, JsonOptions.JsonSerializerOptions); + + internal static JsonNode? SerializeToNode(T obj) => + JsonSerializer.SerializeToNode(obj, JsonOptions.JsonSerializerOptions); + + internal static byte[] SerializeToUtf8Bytes(T obj) => + JsonSerializer.SerializeToUtf8Bytes(obj, JsonOptions.JsonSerializerOptions); + + internal static string SerializeWithAdditionalProperties( + T obj, + object? additionalProperties = null + ) + { + if (additionalProperties is null) + { + return Serialize(obj); + } + var additionalPropertiesJsonNode = SerializeToNode(additionalProperties); + if (additionalPropertiesJsonNode is not JsonObject additionalPropertiesJsonObject) + { + throw new InvalidOperationException( + "The additional properties must serialize to a JSON object." + ); + } + var jsonNode = SerializeToNode(obj); + if (jsonNode is not JsonObject jsonObject) + { + throw new InvalidOperationException( + "The serialized object must be a JSON object to add properties." + ); + } + MergeJsonObjects(jsonObject, additionalPropertiesJsonObject); + return jsonObject.ToJsonString(JsonOptions.JsonSerializerOptions); + } + + private static void MergeJsonObjects(JsonObject baseObject, JsonObject overrideObject) + { + foreach (var property in overrideObject) + { + if (!baseObject.TryGetPropertyValue(property.Key, out JsonNode? existingValue)) + { + baseObject[property.Key] = property.Value is not null + ? JsonNode.Parse(property.Value.ToJsonString()) + : null; + continue; + } + if ( + existingValue is JsonObject nestedBaseObject + && property.Value is JsonObject nestedOverrideObject + ) + { + // If both values are objects, recursively merge them. + MergeJsonObjects(nestedBaseObject, nestedOverrideObject); + continue; + } + // Otherwise, the overrideObject takes precedence. + baseObject[property.Key] = property.Value is not null + ? JsonNode.Parse(property.Value.ToJsonString()) + : null; + } + } + + internal static T Deserialize(string json) => + JsonSerializer.Deserialize(json, JsonOptions.JsonSerializerOptions)!; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/JsonRequest.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/JsonRequest.cs new file mode 100644 index 000000000000..d7794d7ba46b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/JsonRequest.cs @@ -0,0 +1,36 @@ +using global::System.Net.Http; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// The request object to be sent for JSON APIs. +/// +internal record JsonRequest : BaseRequest +{ + internal object? Body { get; init; } + + internal override HttpContent? CreateContent() + { + if (Body is null && Options?.AdditionalBodyProperties is null) + { + return null; + } + + var (encoding, charset, mediaType) = ParseContentTypeOrDefault( + ContentType, + Utf8NoBom, + "application/json" + ); + var content = new StringContent( + JsonUtils.SerializeWithAdditionalProperties(Body, Options?.AdditionalBodyProperties), + encoding, + mediaType + ); + if (string.IsNullOrEmpty(charset) && content.Headers.ContentType is not null) + { + content.Headers.ContentType.CharSet = ""; + } + + return content; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/MultipartFormRequest.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/MultipartFormRequest.cs new file mode 100644 index 000000000000..41654f9c09e1 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/MultipartFormRequest.cs @@ -0,0 +1,294 @@ +using global::System.Net.Http; +using global::System.Net.Http.Headers; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// The request object to be sent for multipart form data. +/// +internal record MultipartFormRequest : BaseRequest +{ + private readonly List> _partAdders = []; + + internal void AddJsonPart(string name, object? value) => AddJsonPart(name, value, null); + + internal void AddJsonPart(string name, object? value, string? contentType) + { + if (value is null) + { + return; + } + + _partAdders.Add(form => + { + var (encoding, charset, mediaType) = ParseContentTypeOrDefault( + contentType, + Utf8NoBom, + "application/json" + ); + var content = new StringContent(JsonUtils.Serialize(value), encoding, mediaType); + if (string.IsNullOrEmpty(charset) && content.Headers.ContentType is not null) + { + content.Headers.ContentType.CharSet = ""; + } + + form.Add(content, name); + }); + } + + internal void AddJsonParts(string name, IEnumerable? value) => + AddJsonParts(name, value, null); + + internal void AddJsonParts(string name, IEnumerable? value, string? contentType) + { + if (value is null) + { + return; + } + + foreach (var item in value) + { + AddJsonPart(name, item, contentType); + } + } + + internal void AddJsonParts(string name, IEnumerable? value) => + AddJsonParts(name, value, null); + + internal void AddJsonParts(string name, IEnumerable? value, string? contentType) + { + if (value is null) + { + return; + } + + foreach (var item in value) + { + AddJsonPart(name, item, contentType); + } + } + + internal void AddStringPart(string name, object? value) => AddStringPart(name, value, null); + + internal void AddStringPart(string name, object? value, string? contentType) + { + if (value is null) + { + return; + } + + AddStringPart(name, ValueConvert.ToString(value), contentType); + } + + internal void AddStringPart(string name, string? value) => AddStringPart(name, value, null); + + internal void AddStringPart(string name, string? value, string? contentType) + { + if (value is null) + { + return; + } + + _partAdders.Add(form => + { + var (encoding, charset, mediaType) = ParseContentTypeOrDefault( + contentType, + Utf8NoBom, + "text/plain" + ); + var content = new StringContent(value, encoding, mediaType); + if (string.IsNullOrEmpty(charset) && content.Headers.ContentType is not null) + { + content.Headers.ContentType.CharSet = ""; + } + + form.Add(content, name); + }); + } + + internal void AddStringParts(string name, IEnumerable? value) => + AddStringParts(name, value, null); + + internal void AddStringParts(string name, IEnumerable? value, string? contentType) + { + if (value is null) + { + return; + } + + AddStringPart(name, ValueConvert.ToString(value), contentType); + } + + internal void AddStringParts(string name, IEnumerable? value) => + AddStringParts(name, value, null); + + internal void AddStringParts(string name, IEnumerable? value, string? contentType) + { + if (value is null) + { + return; + } + + foreach (var item in value) + { + AddStringPart(name, item, contentType); + } + } + + internal void AddStreamPart(string name, Stream? stream, string? fileName) => + AddStreamPart(name, stream, fileName, null); + + internal void AddStreamPart(string name, Stream? stream, string? fileName, string? contentType) + { + if (stream is null) + { + return; + } + + _partAdders.Add(form => + { + var content = new StreamContent(stream) + { + Headers = + { + ContentType = MediaTypeHeaderValue.Parse( + contentType ?? "application/octet-stream" + ), + }, + }; + + if (fileName is not null) + { + form.Add(content, name, fileName); + } + else + { + form.Add(content, name); + } + }); + } + + internal void AddFileParameterPart(string name, Stream? stream) => + AddStreamPart(name, stream, null, null); + + internal void AddFileParameterPart(string name, FileParameter? file) => + AddFileParameterPart(name, file, null); + + internal void AddFileParameterPart( + string name, + FileParameter? file, + string? fallbackContentType + ) => + AddStreamPart(name, file?.Stream, file?.FileName, file?.ContentType ?? fallbackContentType); + + internal void AddFileParameterParts(string name, IEnumerable? files) => + AddFileParameterParts(name, files, null); + + internal void AddFileParameterParts( + string name, + IEnumerable? files, + string? fallbackContentType + ) + { + if (files is null) + { + return; + } + + foreach (var file in files) + { + AddFileParameterPart(name, file, fallbackContentType); + } + } + + internal void AddFormEncodedPart(string name, object? value) => + AddFormEncodedPart(name, value, null); + + internal void AddFormEncodedPart(string name, object? value, string? contentType) + { + if (value is null) + { + return; + } + + _partAdders.Add(form => + { + var content = FormUrlEncoder.EncodeAsForm(value); + if (!string.IsNullOrEmpty(contentType)) + { + content.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType); + } + + form.Add(content, name); + }); + } + + internal void AddFormEncodedParts(string name, IEnumerable? value) => + AddFormEncodedParts(name, value, null); + + internal void AddFormEncodedParts(string name, IEnumerable? value, string? contentType) + { + if (value is null) + { + return; + } + + foreach (var item in value) + { + AddFormEncodedPart(name, item, contentType); + } + } + + internal void AddExplodedFormEncodedPart(string name, object? value) => + AddExplodedFormEncodedPart(name, value, null); + + internal void AddExplodedFormEncodedPart(string name, object? value, string? contentType) + { + if (value is null) + { + return; + } + + _partAdders.Add(form => + { + var content = FormUrlEncoder.EncodeAsExplodedForm(value); + if (!string.IsNullOrEmpty(contentType)) + { + content.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType); + } + + form.Add(content, name); + }); + } + + internal void AddExplodedFormEncodedParts(string name, IEnumerable? value) => + AddExplodedFormEncodedParts(name, value, null); + + internal void AddExplodedFormEncodedParts( + string name, + IEnumerable? value, + string? contentType + ) + { + if (value is null) + { + return; + } + + foreach (var item in value) + { + AddExplodedFormEncodedPart(name, item, contentType); + } + } + + internal override HttpContent CreateContent() + { + var form = new MultipartFormDataContent(); + foreach (var adder in _partAdders) + { + adder(form); + } + + return form; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/NullableAttribute.cs new file mode 100644 index 000000000000..4f8c34c7dcd3 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/NullableAttribute.cs @@ -0,0 +1,18 @@ +namespace SeedCsharpXmlEntities.Core; + +/// +/// Marks a property as nullable in the OpenAPI specification. +/// When applied to Optional<T> properties, this indicates that null values should be +/// written to JSON when the optional is defined with null. +/// +/// +/// For regular (required) properties: +/// - Without [Nullable]: null values are invalid (omit from JSON at runtime) +/// - With [Nullable]: null values are written to JSON +/// +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON +/// +[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] +public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/OneOfSerializer.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/OneOfSerializer.cs new file mode 100644 index 000000000000..2dd8f5915427 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/OneOfSerializer.cs @@ -0,0 +1,190 @@ +using global::System.Reflection; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using OneOf; + +namespace SeedCsharpXmlEntities.Core; + +internal class OneOfSerializer : JsonConverter +{ + public override IOneOf? Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType is JsonTokenType.Null) + return default; + + var json = JsonElement.ParseValue(ref reader); + + IOneOf? firstMatch = null; + IOneOf? bestMatch = null; + + foreach (var (type, cast) in GetOneOfTypes(typeToConvert)) + { + try + { + var result = JsonSerializer.Deserialize(json, type, options); + var oneOf = (IOneOf)cast.Invoke(null, [result])!; + firstMatch ??= oneOf; + + if (!ContainsJsonElement(result)) + { + bestMatch = oneOf; + break; + } + } + catch (JsonException) { } + } + + return bestMatch + ?? firstMatch + ?? throw new JsonException( + $"Cannot deserialize into one of the supported types for {typeToConvert}" + ); + } + + /// + /// Checks if the deserialized object is or contains a raw JsonElement value, + /// indicating the deserializer used a catch-all strategy rather than + /// strongly-typed deserialization. + /// + private static bool ContainsJsonElement(object? result) + { + if (result == null || result is JsonElement) + return true; + + foreach ( + var prop in result.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance) + ) + { + if (prop.GetCustomAttribute() != null) + continue; + if (prop.GetCustomAttribute() != null) + continue; + + try + { + if (prop.GetValue(result) is JsonElement) + return true; + } + catch + { + // Ignore inaccessible properties + } + } + + return false; + } + + public override void Write(Utf8JsonWriter writer, IOneOf value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value.Value, options); + } + + public override IOneOf ReadAsPropertyName( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + var stringValue = reader.GetString(); + if (stringValue == null) + throw new JsonException("Cannot deserialize null property name into OneOf type"); + + // Try to deserialize the string value into one of the supported types + foreach (var (type, cast) in GetOneOfTypes(typeToConvert)) + { + try + { + // For primitive types, try direct conversion + if (type == typeof(string)) + { + return (IOneOf)cast.Invoke(null, [stringValue])!; + } + + // For other types, try to deserialize from JSON string + var result = JsonSerializer.Deserialize($"\"{stringValue}\"", type, options); + if (result != null) + { + return (IOneOf)cast.Invoke(null, [result])!; + } + } + catch { } + } + + // If no type-specific deserialization worked, default to string if available + var stringType = GetOneOfTypes(typeToConvert).FirstOrDefault(t => t.type == typeof(string)); + if (stringType != default) + { + return (IOneOf)stringType.cast.Invoke(null, [stringValue])!; + } + + throw new JsonException( + $"Cannot deserialize dictionary key '{stringValue}' into one of the supported types for {typeToConvert}" + ); + } + + public override void WriteAsPropertyName( + Utf8JsonWriter writer, + IOneOf value, + JsonSerializerOptions options + ) + { + // Serialize the underlying value to a string suitable for use as a dictionary key + var stringValue = value.Value?.ToString() ?? "null"; + writer.WritePropertyName(stringValue); + } + + private static (global::System.Type type, MethodInfo cast)[] GetOneOfTypes( + global::System.Type typeToConvert + ) + { + var type = typeToConvert; + if (Nullable.GetUnderlyingType(type) is { } underlyingType) + { + type = underlyingType; + } + + var casts = type.GetRuntimeMethods() + .Where(m => m.IsSpecialName && m.Name == "op_Implicit") + .ToArray(); + while (type is not null) + { + if ( + type.IsGenericType + && (type.Name.StartsWith("OneOf`") || type.Name.StartsWith("OneOfBase`")) + ) + { + var genericArguments = type.GetGenericArguments(); + if (genericArguments.Length == 1) + { + return [(genericArguments[0], casts[0])]; + } + + // if object type is present, make sure it is last + var indexOfObjectType = Array.IndexOf(genericArguments, typeof(object)); + if (indexOfObjectType != -1 && genericArguments.Length - 1 != indexOfObjectType) + { + genericArguments = genericArguments + .OrderBy(t => t == typeof(object) ? 1 : 0) + .ToArray(); + } + + return genericArguments + .Select(t => (t, casts.First(c => c.GetParameters()[0].ParameterType == t))) + .ToArray(); + } + + type = type.BaseType; + } + + throw new InvalidOperationException($"{type} isn't OneOf or OneOfBase"); + } + + public override bool CanConvert(global::System.Type typeToConvert) + { + return typeof(IOneOf).IsAssignableFrom(typeToConvert); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Optional.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Optional.cs new file mode 100644 index 000000000000..2643c552ec69 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Optional.cs @@ -0,0 +1,474 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Non-generic interface for Optional types to enable reflection-free checks. +/// +public interface IOptional +{ + /// + /// Returns true if the value is defined (set), even if the value is null. + /// + bool IsDefined { get; } + + /// + /// Gets the boxed value. Returns null if undefined or if the value is null. + /// + object? GetBoxedValue(); +} + +/// +/// Represents a field that can be "not set" (undefined) vs "explicitly set" (defined). +/// Use this for HTTP PATCH requests where you need to distinguish between: +/// +/// Undefined: Don't send this field (leave it unchanged on the server) +/// Defined with null: Send null (clear the field on the server) +/// Defined with value: Send the value (update the field on the server) +/// +/// +/// The type of the value. Use nullable types (T?) for fields that can be null. +/// +/// For nullable string fields, use Optional<string?>: +/// +/// public class UpdateUserRequest +/// { +/// public Optional<string?> Name { get; set; } = Optional<string?>.Undefined; +/// } +/// +/// var request = new UpdateUserRequest +/// { +/// Name = "John" // Will send: { "name": "John" } +/// }; +/// +/// var request2 = new UpdateUserRequest +/// { +/// Name = Optional<string?>.Of(null) // Will send: { "name": null } +/// }; +/// +/// var request3 = new UpdateUserRequest(); // Will send: {} (name not included) +/// +/// +public readonly struct Optional : IOptional, IEquatable> +{ + private readonly T _value; + private readonly bool _isDefined; + + private Optional(T value, bool isDefined) + { + _value = value; + _isDefined = isDefined; + } + + /// + /// Creates an undefined value - the field will not be included in the HTTP request. + /// Use this as the default value for optional fields. + /// + /// + /// + /// public Optional<string?> Email { get; set; } = Optional<string?>.Undefined; + /// + /// + public static Optional Undefined => new(default!, false); + + /// + /// Creates a defined value - the field will be included in the HTTP request. + /// The value can be null if T is a nullable type. + /// + /// The value to set. Can be null if T is nullable (e.g., string?, int?). + /// + /// + /// // Set to a value + /// request.Name = Optional<string?>.Of("John"); + /// + /// // Set to null (clears the field) + /// request.Email = Optional<string?>.Of(null); + /// + /// // Or use implicit conversion + /// request.Name = "John"; // Same as Of("John") + /// request.Email = null; // Same as Of(null) + /// + /// + public static Optional Of(T value) => new(value, true); + + /// + /// Returns true if the field is defined (set), even if the value is null. + /// Use this to determine if the field should be included in the HTTP request. + /// + /// + /// + /// if (request.Name.IsDefined) + /// { + /// requestBody["name"] = request.Name.Value; // Include in request (can be null) + /// } + /// + /// + public bool IsDefined => _isDefined; + + /// + /// Returns true if the field is undefined (not set). + /// Use this to check if the field should be excluded from the HTTP request. + /// + /// + /// + /// if (request.Email.IsUndefined) + /// { + /// // Don't include email in the request - leave it unchanged + /// } + /// + /// + public bool IsUndefined => !_isDefined; + + /// + /// Gets the value. The value may be null if T is a nullable type. + /// + /// Thrown if the value is undefined. + /// + /// Always check before accessing Value, or use instead. + /// + /// + /// + /// if (request.Name.IsDefined) + /// { + /// string? name = request.Name.Value; // Safe - can be null if Optional<string?> + /// } + /// + /// // Or check for null explicitly + /// if (request.Email.IsDefined && request.Email.Value is null) + /// { + /// // Email is explicitly set to null (clear it) + /// } + /// + /// + public T Value + { + get + { + if (!_isDefined) + throw new InvalidOperationException("Optional value is undefined"); + return _value; + } + } + + /// + /// Gets the value if defined, otherwise returns the specified default value. + /// Note: If the value is defined as null, this returns null (not the default). + /// + /// The value to return if undefined. + /// The actual value if defined (can be null), otherwise the default value. + /// + /// + /// string name = request.Name.GetValueOrDefault("Anonymous"); + /// // If Name is undefined: returns "Anonymous" + /// // If Name is Of(null): returns null + /// // If Name is Of("John"): returns "John" + /// + /// + public T GetValueOrDefault(T defaultValue = default!) + { + return _isDefined ? _value : defaultValue; + } + + /// + /// Tries to get the value. Returns true if the value is defined (even if null). + /// + /// + /// When this method returns, contains the value if defined, or default(T) if undefined. + /// The value may be null if T is nullable. + /// + /// True if the value is defined; otherwise, false. + /// + /// + /// if (request.Email.TryGetValue(out var email)) + /// { + /// requestBody["email"] = email; // email can be null + /// } + /// else + /// { + /// // Email is undefined - don't include in request + /// } + /// + /// + public bool TryGetValue(out T value) + { + if (_isDefined) + { + value = _value; + return true; + } + value = default!; + return false; + } + + /// + /// Implicitly converts a value to Optional<T>.Of(value). + /// This allows natural assignment: request.Name = "John" instead of request.Name = Optional<string?>.Of("John"). + /// + /// The value to convert (can be null if T is nullable). + public static implicit operator Optional(T value) => Of(value); + + /// + /// Returns a string representation of this Optional value. + /// + /// "Undefined" if not set, or "Defined(value)" if set. + public override string ToString() => _isDefined ? $"Defined({_value})" : "Undefined"; + + /// + /// Gets the boxed value. Returns null if undefined or if the value is null. + /// + public object? GetBoxedValue() + { + if (!_isDefined) + return null; + return _value; + } + + /// + public bool Equals(Optional other) => + _isDefined == other._isDefined && EqualityComparer.Default.Equals(_value, other._value); + + /// + public override bool Equals(object? obj) => obj is Optional other && Equals(other); + + /// + public override int GetHashCode() + { + if (!_isDefined) + return 0; + unchecked + { + int hash = 17; + hash = hash * 31 + 1; // _isDefined = true + hash = hash * 31 + (_value is null ? 0 : _value.GetHashCode()); + return hash; + } + } + + /// + /// Determines whether two Optional values are equal. + /// + /// The first Optional to compare. + /// The second Optional to compare. + /// True if the Optional values are equal; otherwise, false. + public static bool operator ==(Optional left, Optional right) => left.Equals(right); + + /// + /// Determines whether two Optional values are not equal. + /// + /// The first Optional to compare. + /// The second Optional to compare. + /// True if the Optional values are not equal; otherwise, false. + public static bool operator !=(Optional left, Optional right) => !left.Equals(right); +} + +/// +/// Extension methods for Optional<T> to simplify common operations. +/// +public static class OptionalExtensions +{ + /// + /// Adds the value to a dictionary if the optional is defined (even if the value is null). + /// This is useful for building JSON request payloads where null values should be included. + /// + /// The type of the optional value. + /// The optional value to add. + /// The dictionary to add to. + /// The key to use in the dictionary. + /// + /// + /// var dict = new Dictionary<string, object?>(); + /// request.Name.AddTo(dict, "name"); // Adds only if Name.IsDefined + /// request.Email.AddTo(dict, "email"); // Adds only if Email.IsDefined + /// + /// + public static void AddTo( + this Optional optional, + Dictionary dictionary, + string key + ) + { + if (optional.IsDefined) + { + dictionary[key] = optional.Value; + } + } + + /// + /// Executes an action if the optional is defined. + /// + /// The type of the optional value. + /// The optional value. + /// The action to execute with the value. + /// + /// + /// request.Name.IfDefined(name => Console.WriteLine($"Name: {name}")); + /// + /// + public static void IfDefined(this Optional optional, Action action) + { + if (optional.IsDefined) + { + action(optional.Value); + } + } + + /// + /// Maps the value to a new type if the optional is defined, otherwise returns undefined. + /// + /// The type of the original value. + /// The type to map to. + /// The optional value to map. + /// The mapping function. + /// An optional containing the mapped value if defined, otherwise undefined. + /// + /// + /// Optional<string?> name = Optional<string?>.Of("John"); + /// Optional<int> length = name.Map(n => n?.Length ?? 0); // Optional.Of(4) + /// + /// + public static Optional Map( + this Optional optional, + Func mapper + ) + { + return optional.IsDefined + ? Optional.Of(mapper(optional.Value)) + : Optional.Undefined; + } + + /// + /// Adds a nullable value to a dictionary only if it is not null. + /// This is useful for regular nullable properties where null means "omit from request". + /// + /// The type of the value (must be a reference type or Nullable<T>). + /// The nullable value to add. + /// The dictionary to add to. + /// The key to use in the dictionary. + /// + /// + /// var dict = new Dictionary<string, object?>(); + /// request.Description.AddIfNotNull(dict, "description"); // Only adds if not null + /// request.Score.AddIfNotNull(dict, "score"); // Only adds if not null + /// + /// + public static void AddIfNotNull( + this T? value, + Dictionary dictionary, + string key + ) + where T : class + { + if (value is not null) + { + dictionary[key] = value; + } + } + + /// + /// Adds a nullable value type to a dictionary only if it has a value. + /// This is useful for regular nullable properties where null means "omit from request". + /// + /// The underlying value type. + /// The nullable value to add. + /// The dictionary to add to. + /// The key to use in the dictionary. + /// + /// + /// var dict = new Dictionary<string, object?>(); + /// request.Age.AddIfNotNull(dict, "age"); // Only adds if HasValue + /// request.Score.AddIfNotNull(dict, "score"); // Only adds if HasValue + /// + /// + public static void AddIfNotNull( + this T? value, + Dictionary dictionary, + string key + ) + where T : struct + { + if (value.HasValue) + { + dictionary[key] = value.Value; + } + } +} + +/// +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. +/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. +/// +public class OptionalJsonConverterFactory : JsonConverterFactory +{ + public override bool CanConvert(global::System.Type typeToConvert) + { + if (!typeToConvert.IsGenericType) + return false; + + return typeToConvert.GetGenericTypeDefinition() == typeof(Optional<>); + } + + public override JsonConverter? CreateConverter( + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + var valueType = typeToConvert.GetGenericArguments()[0]; + var converterType = typeof(OptionalJsonConverter<>).MakeGenericType(valueType); + return (JsonConverter?)global::System.Activator.CreateInstance(converterType); + } +} + +/// +/// JSON converter for Optional<T> that unwraps the value during serialization. +/// The actual property skipping is handled by the OptionalTypeInfoResolver. +/// +public class OptionalJsonConverter : JsonConverter> +{ + public override Optional Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType == JsonTokenType.Null) + { + return Optional.Of(default!); + } + + var value = JsonSerializer.Deserialize(ref reader, options); + return Optional.Of(value!); + } + + public override void Write( + Utf8JsonWriter writer, + Optional value, + JsonSerializerOptions options + ) + { + // This will be called by the serializer + // We need to unwrap and serialize the inner value + // The TypeInfoResolver will handle skipping undefined values + + if (value.IsUndefined) + { + // This shouldn't be called for undefined values due to ShouldSerialize + // But if it is, write null and let the resolver filter it + writer.WriteNullValue(); + return; + } + + // Get the inner value + var innerValue = value.Value; + + // Write null directly if the value is null (don't use JsonSerializer.Serialize for null) + if (innerValue is null) + { + writer.WriteNullValue(); + return; + } + + // Serialize the unwrapped value + JsonSerializer.Serialize(writer, innerValue, options); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/OptionalAttribute.cs new file mode 100644 index 000000000000..00570d0f4680 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/OptionalAttribute.cs @@ -0,0 +1,17 @@ +namespace SeedCsharpXmlEntities.Core; + +/// +/// Marks a property as optional in the OpenAPI specification. +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). +/// +/// +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON +/// +/// Combine with [Nullable] to allow null values: +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) +/// +[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] +public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/AdditionalProperties.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/AdditionalProperties.cs new file mode 100644 index 000000000000..2f84deafb28b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/AdditionalProperties.cs @@ -0,0 +1,353 @@ +using global::System.Collections; +using global::System.Collections.ObjectModel; +using global::System.Text.Json; +using global::System.Text.Json.Nodes; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities; + +public record ReadOnlyAdditionalProperties : ReadOnlyAdditionalProperties +{ + internal ReadOnlyAdditionalProperties() { } + + internal ReadOnlyAdditionalProperties(IDictionary properties) + : base(properties) { } +} + +public record ReadOnlyAdditionalProperties : IReadOnlyDictionary +{ + private readonly Dictionary _extensionData = new(); + private readonly Dictionary _convertedCache = new(); + + internal ReadOnlyAdditionalProperties() + { + _extensionData = new Dictionary(); + _convertedCache = new Dictionary(); + } + + internal ReadOnlyAdditionalProperties(IDictionary properties) + { + _extensionData = new Dictionary(properties.Count); + _convertedCache = new Dictionary(properties.Count); + foreach (var kvp in properties) + { + if (kvp.Value is JsonElement element) + { + _extensionData.Add(kvp.Key, element); + } + else + { + _extensionData[kvp.Key] = JsonUtils.SerializeToElement(kvp.Value); + } + + _convertedCache[kvp.Key] = kvp.Value; + } + } + + private static T ConvertToT(JsonElement value) + { + if (typeof(T) == typeof(JsonElement)) + { + return (T)(object)value; + } + + return value.Deserialize(JsonOptions.JsonSerializerOptions)!; + } + + internal void CopyFromExtensionData(IDictionary extensionData) + { + _extensionData.Clear(); + _convertedCache.Clear(); + foreach (var kvp in extensionData) + { + _extensionData[kvp.Key] = kvp.Value; + if (kvp.Value is T value) + { + _convertedCache[kvp.Key] = value; + } + } + } + + private T GetCached(string key) + { + if (_convertedCache.TryGetValue(key, out var cached)) + { + return cached; + } + + var value = ConvertToT(_extensionData[key]); + _convertedCache[key] = value; + return value; + } + + public IEnumerator> GetEnumerator() + { + return _extensionData + .Select(kvp => new KeyValuePair(kvp.Key, GetCached(kvp.Key))) + .GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public int Count => _extensionData.Count; + + public bool ContainsKey(string key) => _extensionData.ContainsKey(key); + + public bool TryGetValue(string key, out T value) + { + if (_convertedCache.TryGetValue(key, out value!)) + { + return true; + } + + if (_extensionData.TryGetValue(key, out var element)) + { + value = ConvertToT(element); + _convertedCache[key] = value; + return true; + } + + return false; + } + + public T this[string key] => GetCached(key); + + public IEnumerable Keys => _extensionData.Keys; + + public IEnumerable Values => Keys.Select(GetCached); +} + +public record AdditionalProperties : AdditionalProperties +{ + public AdditionalProperties() { } + + public AdditionalProperties(IDictionary properties) + : base(properties) { } +} + +public record AdditionalProperties : IDictionary +{ + private readonly Dictionary _extensionData; + private readonly Dictionary _convertedCache; + + public AdditionalProperties() + { + _extensionData = new Dictionary(); + _convertedCache = new Dictionary(); + } + + public AdditionalProperties(IDictionary properties) + { + _extensionData = new Dictionary(properties.Count); + _convertedCache = new Dictionary(properties.Count); + foreach (var kvp in properties) + { + _extensionData[kvp.Key] = kvp.Value; + _convertedCache[kvp.Key] = kvp.Value; + } + } + + private static T ConvertToT(object? extensionDataValue) + { + return extensionDataValue switch + { + T value => value, + JsonElement jsonElement => jsonElement.Deserialize( + JsonOptions.JsonSerializerOptions + )!, + JsonNode jsonNode => jsonNode.Deserialize(JsonOptions.JsonSerializerOptions)!, + _ => JsonUtils + .SerializeToElement(extensionDataValue) + .Deserialize(JsonOptions.JsonSerializerOptions)!, + }; + } + + internal void CopyFromExtensionData(IDictionary extensionData) + { + _extensionData.Clear(); + _convertedCache.Clear(); + foreach (var kvp in extensionData) + { + _extensionData[kvp.Key] = kvp.Value; + if (kvp.Value is T value) + { + _convertedCache[kvp.Key] = value; + } + } + } + + internal void CopyToExtensionData(IDictionary extensionData) + { + extensionData.Clear(); + foreach (var kvp in _extensionData) + { + extensionData[kvp.Key] = kvp.Value; + } + } + + public JsonObject ToJsonObject() => + ( + JsonUtils.SerializeToNode(_extensionData) + ?? throw new InvalidOperationException( + "Failed to serialize AdditionalProperties to JSON Node." + ) + ).AsObject(); + + public JsonNode ToJsonNode() => + JsonUtils.SerializeToNode(_extensionData) + ?? throw new InvalidOperationException( + "Failed to serialize AdditionalProperties to JSON Node." + ); + + public JsonElement ToJsonElement() => JsonUtils.SerializeToElement(_extensionData); + + public JsonDocument ToJsonDocument() => JsonUtils.SerializeToDocument(_extensionData); + + public IReadOnlyDictionary ToJsonElementDictionary() + { + return new ReadOnlyDictionary( + _extensionData.ToDictionary( + kvp => kvp.Key, + kvp => + { + if (kvp.Value is JsonElement jsonElement) + { + return jsonElement; + } + + return JsonUtils.SerializeToElement(kvp.Value); + } + ) + ); + } + + public ICollection Keys => _extensionData.Keys; + + public ICollection Values + { + get + { + var values = new T[_extensionData.Count]; + var i = 0; + foreach (var key in Keys) + { + values[i++] = GetCached(key); + } + + return values; + } + } + + private T GetCached(string key) + { + if (_convertedCache.TryGetValue(key, out var value)) + { + return value; + } + + value = ConvertToT(_extensionData[key]); + _convertedCache.Add(key, value); + return value; + } + + private void SetCached(string key, T value) + { + _extensionData[key] = value; + _convertedCache[key] = value; + } + + private void AddCached(string key, T value) + { + _extensionData.Add(key, value); + _convertedCache.Add(key, value); + } + + private bool RemoveCached(string key) + { + var isRemoved = _extensionData.Remove(key); + _convertedCache.Remove(key); + return isRemoved; + } + + public int Count => _extensionData.Count; + public bool IsReadOnly => false; + + public T this[string key] + { + get => GetCached(key); + set => SetCached(key, value); + } + + public void Add(string key, T value) => AddCached(key, value); + + public void Add(KeyValuePair item) => AddCached(item.Key, item.Value); + + public bool Remove(string key) => RemoveCached(key); + + public bool Remove(KeyValuePair item) => RemoveCached(item.Key); + + public bool ContainsKey(string key) => _extensionData.ContainsKey(key); + + public bool Contains(KeyValuePair item) + { + return _extensionData.ContainsKey(item.Key) + && EqualityComparer.Default.Equals(GetCached(item.Key), item.Value); + } + + public bool TryGetValue(string key, out T value) + { + if (_convertedCache.TryGetValue(key, out value!)) + { + return true; + } + + if (_extensionData.TryGetValue(key, out var extensionDataValue)) + { + value = ConvertToT(extensionDataValue); + _convertedCache[key] = value; + return true; + } + + return false; + } + + public void Clear() + { + _extensionData.Clear(); + _convertedCache.Clear(); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + if (array is null) + { + throw new ArgumentNullException(nameof(array)); + } + + if (arrayIndex < 0 || arrayIndex > array.Length) + { + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + } + + if (array.Length - arrayIndex < _extensionData.Count) + { + throw new ArgumentException( + "The array does not have enough space to copy the elements." + ); + } + + foreach (var kvp in _extensionData) + { + array[arrayIndex++] = new KeyValuePair(kvp.Key, GetCached(kvp.Key)); + } + } + + public IEnumerator> GetEnumerator() + { + return _extensionData + .Select(kvp => new KeyValuePair(kvp.Key, GetCached(kvp.Key))) + .GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/ClientOptions.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/ClientOptions.cs new file mode 100644 index 000000000000..d00874461f3c --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/ClientOptions.cs @@ -0,0 +1,84 @@ +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities; + +[Serializable] +public partial class ClientOptions +{ + /// + /// The http headers sent with the request. + /// + internal Headers Headers { get; init; } = new(); + + /// + /// The Base URL for the API. + /// + public string BaseUrl { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = ""; + + /// + /// The http client used to make requests. + /// + public HttpClient HttpClient { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = DefaultHttpClientFactory.Create(); + + /// + /// Additional headers to be sent with HTTP requests. + /// Headers with matching keys will be overwritten by headers set on the request. + /// + public IEnumerable> AdditionalHeaders { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = []; + + /// + /// The max number of retries to attempt. + /// + public int MaxRetries { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = 2; + + /// + /// The timeout for the request. + /// + public TimeSpan Timeout { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = TimeSpan.FromMilliseconds(30000); + + /// + /// Clones this and returns a new instance + /// + internal ClientOptions Clone() + { + return new ClientOptions + { + BaseUrl = BaseUrl, + HttpClient = HttpClient, + MaxRetries = MaxRetries, + Timeout = Timeout, + Headers = new Headers(new Dictionary(Headers)), + AdditionalHeaders = AdditionalHeaders, + }; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/FileParameter.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/FileParameter.cs new file mode 100644 index 000000000000..a6c1154b282b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/FileParameter.cs @@ -0,0 +1,63 @@ +namespace SeedCsharpXmlEntities; + +/// +/// File parameter for uploading files. +/// +public record FileParameter : IDisposable +#if NET6_0_OR_GREATER + , IAsyncDisposable +#endif +{ + private bool _disposed; + + /// + /// The name of the file to be uploaded. + /// + public string? FileName { get; set; } + + /// + /// The content type of the file to be uploaded. + /// + public string? ContentType { get; set; } + + /// + /// The content of the file to be uploaded. + /// + public required Stream Stream { get; set; } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + if (disposing) + { + Stream.Dispose(); + } + + _disposed = true; + } + +#if NET6_0_OR_GREATER + /// + public async ValueTask DisposeAsync() + { + if (!_disposed) + { + await Stream.DisposeAsync().ConfigureAwait(false); + _disposed = true; + } + + GC.SuppressFinalize(this); + } +#endif + + public static implicit operator FileParameter(Stream stream) => new() { Stream = stream }; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/RawResponse.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/RawResponse.cs new file mode 100644 index 000000000000..52f1bd97d565 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/RawResponse.cs @@ -0,0 +1,24 @@ +using global::System.Net; + +namespace SeedCsharpXmlEntities; + +/// +/// Contains HTTP response metadata including status code, URL, and headers. +/// +public record RawResponse +{ + /// + /// The HTTP status code of the response. + /// + public required HttpStatusCode StatusCode { get; init; } + + /// + /// The request URL that generated this response. + /// + public required Uri Url { get; init; } + + /// + /// The HTTP response headers. + /// + public required Core.ResponseHeaders Headers { get; init; } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/RequestOptions.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/RequestOptions.cs new file mode 100644 index 000000000000..1d63eb845e2d --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/RequestOptions.cs @@ -0,0 +1,86 @@ +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities; + +[Serializable] +public partial class RequestOptions : IRequestOptions +{ + /// + /// The Base URL for the API. + /// + public string? BaseUrl { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// The http client used to make requests. + /// + public HttpClient? HttpClient { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// Additional headers to be sent with the request. + /// Headers previously set with matching keys will be overwritten. + /// + public IEnumerable> AdditionalHeaders { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = []; + + /// + /// The max number of retries to attempt. + /// + public int? MaxRetries { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// The timeout for the request. + /// + public TimeSpan? Timeout { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// Additional query parameters sent with the request. + /// + public IEnumerable> AdditionalQueryParameters { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = Enumerable.Empty>(); + + /// + /// Additional body properties sent with the request. + /// This is only applied to JSON requests. + /// + public object? AdditionalBodyProperties { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesApiException.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesApiException.cs new file mode 100644 index 000000000000..3f814522c310 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesApiException.cs @@ -0,0 +1,28 @@ +namespace SeedCsharpXmlEntities; + +/// +/// This exception type will be thrown for any non-2XX API responses. +/// +public class SeedCsharpXmlEntitiesApiException( + string message, + int statusCode, + object body, + Exception? innerException = null, + SeedCsharpXmlEntities.RawResponse? rawResponse = null +) : SeedCsharpXmlEntitiesException(message, innerException) +{ + /// + /// The error code of the response that triggered the exception. + /// + public int StatusCode => statusCode; + + /// + /// The body of the response that triggered the exception. + /// + public object Body => body; + + /// + /// The raw HTTP response (status code, URL, headers) that triggered the exception, if available. + /// + public SeedCsharpXmlEntities.RawResponse? RawResponse => rawResponse; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesException.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesException.cs new file mode 100644 index 000000000000..6801d0fab3c5 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesException.cs @@ -0,0 +1,7 @@ +namespace SeedCsharpXmlEntities; + +/// +/// Base exception class for all exceptions thrown by the SDK. +/// +public class SeedCsharpXmlEntitiesException(string message, Exception? innerException = null) + : Exception(message, innerException); diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/Version.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/Version.cs new file mode 100644 index 000000000000..00b2fffd7856 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/Version.cs @@ -0,0 +1,7 @@ +namespace SeedCsharpXmlEntities; + +[Serializable] +internal class Version +{ + public const string Current = "0.0.1"; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/WithRawResponse.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/WithRawResponse.cs new file mode 100644 index 000000000000..b3a34aeaa71f --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/WithRawResponse.cs @@ -0,0 +1,18 @@ +namespace SeedCsharpXmlEntities; + +/// +/// Wraps a parsed response value with its raw HTTP response metadata. +/// +/// The type of the parsed response data. +public readonly struct WithRawResponse +{ + /// + /// The parsed response data. + /// + public required T Data { get; init; } + + /// + /// The raw HTTP response metadata. + /// + public required RawResponse RawResponse { get; init; } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseStream.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseStream.cs new file mode 100644 index 000000000000..45e8188e2b17 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseStream.cs @@ -0,0 +1,66 @@ +using global::System.Collections.Generic; +using global::System.Runtime.CompilerServices; +using global::System.Threading; +using global::System.Threading.Tasks; + +namespace SeedCsharpXmlEntities; + +/// +/// A streaming wrapper that provides dual-mode access to a streaming endpoint: +/// - Direct await foreach iterates the parsed stream values (zero-allocation path for common case) +/// - .WithRawResponse() yields the underlying exposing both the stream and raw response metadata +/// +/// The element type of the parsed stream. +public readonly struct WithRawResponseStream : IAsyncEnumerable +{ + private readonly Task>> _task; + private readonly CancellationToken _originalCancellationToken; + + /// + /// Creates a new WithRawResponseStream wrapping the given task that opens the underlying HTTP response. + /// + /// The task opening the HTTP response and producing the parsed stream. + /// + /// The cancellation token supplied at the SDK call site. Linked with any token supplied via + /// .WithCancellation(...) on the enumerator so both cancel the inner reads. + /// + public WithRawResponseStream( + Task>> task, + CancellationToken cancellationToken = default + ) + { + _task = task; + _originalCancellationToken = cancellationToken; + } + + /// + /// Returns the underlying task that yields both the stream and raw response metadata once headers are received. + /// + public Task>> WithRawResponse() => _task; + + /// + /// Returns an enumerator that iterates the parsed stream values. Awaits the underlying HTTP response, then yields each parsed element from the body stream. + /// + public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) => + EnumerateAsync(_task, _originalCancellationToken, cancellationToken) + .GetAsyncEnumerator(cancellationToken); + + private static async IAsyncEnumerable EnumerateAsync( + Task>> task, + CancellationToken originalCancellationToken, + [EnumeratorCancellation] CancellationToken cancellationToken + ) + { + using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource( + originalCancellationToken, + cancellationToken + ); + var wrapped = await task.ConfigureAwait(false); + await foreach ( + var item in wrapped.Data.WithCancellation(linkedCts.Token).ConfigureAwait(false) + ) + { + yield return item; + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseTask.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseTask.cs new file mode 100644 index 000000000000..21cfc200c565 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseTask.cs @@ -0,0 +1,187 @@ +using global::System.Runtime.CompilerServices; + +namespace SeedCsharpXmlEntities; + +/// +/// A task-like type that wraps Task<WithRawResponse<T>> and provides dual-mode awaiting: +/// - Direct await yields just T (zero-allocation path for common case) +/// - .WithRawResponse() yields WithRawResponse<T> (when raw response metadata is needed) +/// +/// The type of the parsed response data. +public readonly struct WithRawResponseTask +{ + private readonly global::System.Threading.Tasks.Task> _task; + + /// + /// Creates a new WithRawResponseTask wrapping the given task. + /// + public WithRawResponseTask(global::System.Threading.Tasks.Task> task) + { + _task = task; + } + + /// + /// Returns the underlying task that yields both the data and raw response metadata. + /// + public global::System.Threading.Tasks.Task> WithRawResponse() => _task; + + /// + /// Gets the custom awaiter that unwraps to just T when awaited. + /// + public Awaiter GetAwaiter() => new(_task.GetAwaiter()); + + /// + /// Configures the awaiter to continue on the captured context or not. + /// + public ConfiguredTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) => + new(_task.ConfigureAwait(continueOnCapturedContext)); + + /// + /// Implicitly converts WithRawResponseTask<T> to global::System.Threading.Tasks.Task<T> for backward compatibility. + /// The resulting task will yield just the data when awaited. + /// + public static implicit operator global::System.Threading.Tasks.Task( + WithRawResponseTask task + ) + { + return task._task.ContinueWith( + t => t.Result.Data, + TaskContinuationOptions.ExecuteSynchronously + ); + } + + /// + /// Custom awaiter that unwraps WithRawResponse<T> to just T. + /// + public readonly struct Awaiter : ICriticalNotifyCompletion + { + private readonly TaskAwaiter> _awaiter; + + internal Awaiter(TaskAwaiter> awaiter) + { + _awaiter = awaiter; + } + + /// + /// Gets whether the underlying task has completed. + /// + public bool IsCompleted => _awaiter.IsCompleted; + + /// + /// Gets the result, unwrapping to just the data. + /// + public T GetResult() => _awaiter.GetResult().Data; + + /// + /// Schedules the continuation action. + /// + public void OnCompleted(global::System.Action continuation) => + _awaiter.OnCompleted(continuation); + + /// + /// Schedules the continuation action without capturing the execution context. + /// + public void UnsafeOnCompleted(global::System.Action continuation) => + _awaiter.UnsafeOnCompleted(continuation); + } + + /// + /// Awaitable type returned by ConfigureAwait that unwraps to just T. + /// + public readonly struct ConfiguredTaskAwaitable + { + private readonly ConfiguredTaskAwaitable> _configuredTask; + + internal ConfiguredTaskAwaitable(ConfiguredTaskAwaitable> configuredTask) + { + _configuredTask = configuredTask; + } + + /// + /// Gets the configured awaiter that unwraps to just T. + /// + public ConfiguredAwaiter GetAwaiter() => new(_configuredTask.GetAwaiter()); + + /// + /// Custom configured awaiter that unwraps WithRawResponse<T> to just T. + /// + public readonly struct ConfiguredAwaiter : ICriticalNotifyCompletion + { + private readonly ConfiguredTaskAwaitable< + WithRawResponse + >.ConfiguredTaskAwaiter _awaiter; + + internal ConfiguredAwaiter( + ConfiguredTaskAwaitable>.ConfiguredTaskAwaiter awaiter + ) + { + _awaiter = awaiter; + } + + /// + /// Gets whether the underlying task has completed. + /// + public bool IsCompleted => _awaiter.IsCompleted; + + /// + /// Gets the result, unwrapping to just the data. + /// + public T GetResult() => _awaiter.GetResult().Data; + + /// + /// Schedules the continuation action. + /// + public void OnCompleted(global::System.Action continuation) => + _awaiter.OnCompleted(continuation); + + /// + /// Schedules the continuation action without capturing the execution context. + /// + public void UnsafeOnCompleted(global::System.Action continuation) => + _awaiter.UnsafeOnCompleted(continuation); + } + } +} + +/// +/// A task-like type that wraps Task<RawResponse> and provides dual-mode awaiting for endpoints with no response body: +/// - Direct await completes with no value (void semantics) +/// - .WithRawResponse() yields RawResponse (when raw response metadata is needed) +/// +public readonly struct WithRawResponseTask +{ + private readonly global::System.Threading.Tasks.Task _task; + + /// + /// Creates a new WithRawResponseTask wrapping the given task. + /// + public WithRawResponseTask(global::System.Threading.Tasks.Task task) + { + _task = task; + } + + /// + /// Returns the underlying task that yields raw response metadata. + /// + public global::System.Threading.Tasks.Task WithRawResponse() => _task; + + /// + /// Awaiter delegates to the non-generic Task, completing with no value. + /// + public TaskAwaiter GetAwaiter() => ((global::System.Threading.Tasks.Task)_task).GetAwaiter(); + + /// + /// Configures the awaiter to continue on the captured context or not. The configured awaitable completes with no value. + /// + public global::System.Runtime.CompilerServices.ConfiguredTaskAwaitable ConfigureAwait( + bool continueOnCapturedContext + ) => ((global::System.Threading.Tasks.Task)_task).ConfigureAwait(continueOnCapturedContext); + + /// + /// Implicitly converts WithRawResponseTask to global::System.Threading.Tasks.Task for backward compatibility. + /// + public static implicit operator global::System.Threading.Tasks.Task(WithRawResponseTask task) + { + return task._task; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/QueryStringBuilder.cs new file mode 100644 index 000000000000..1bd6d3fb9c78 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/QueryStringBuilder.cs @@ -0,0 +1,656 @@ +using global::System.Buffers; +using global::System.Runtime.CompilerServices; +#if !NET6_0_OR_GREATER +using global::System.Text; +#endif + +namespace SeedCsharpXmlEntities.Core; + +/// +/// High-performance query string builder with RFC 3986 compliant percent-encoding. +/// Uses span-based APIs on .NET 6+ and StringBuilder fallback for older targets. +/// +/// RFC 3986 defines the following relevant productions: +/// pchar = unreserved / pct-encoded / sub-delims / ":" / "@" +/// query = *( pchar / "/" / "?" ) +/// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" +/// sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" +/// +/// Three encoding contexts are distinguished: +/// Path segment (pchar): unreserved + sub-delims + ":" + "@" +/// Query key: query chars minus "&", "=", "+", ";", "#" +/// Query value: query chars minus "&", "+", ";", "#" +/// +/// ";" is percent-encoded in queries even though RFC 3986 permits it: it is a +/// legacy parameter separator that many servers and frameworks still split on, +/// so leaving it raw truncates the value. +/// +internal static class QueryStringBuilder +{ + // ────────────────────────────────────────────────────────────────────── + // RFC 3986 character sets + // + // Query key safe: unreserved + (sub-delims \ {& = + ;}) + : @ / ? + // Query value safe: unreserved + (sub-delims \ {& + ;}) + : @ / ? + // Path segment safe: unreserved + sub-delims + : @ + // ────────────────────────────────────────────────────────────────────── + +#if NET8_0_OR_GREATER + private static readonly SearchValues SafeQueryKeyChars = SearchValues.Create( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!$'()*,:@/?" + ); + + private static readonly SearchValues SafeQueryValueChars = SearchValues.Create( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!$'()*,=:@/?" + ); + + private static readonly SearchValues SafePathChars = SearchValues.Create( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!$&'()*+,;=:@" + ); +#else + private const string SafeQueryKeyChars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!$'()*,:@/?"; + + private const string SafeQueryValueChars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!$'()*,=:@/?"; + + private const string SafePathChars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!$&'()*+,;=:@"; +#endif + +#if NET7_0_OR_GREATER + private static ReadOnlySpan UpperHexChars => "0123456789ABCDEF"u8; +#else + private static readonly byte[] UpperHexChars = + { + (byte)'0', + (byte)'1', + (byte)'2', + (byte)'3', + (byte)'4', + (byte)'5', + (byte)'6', + (byte)'7', + (byte)'8', + (byte)'9', + (byte)'A', + (byte)'B', + (byte)'C', + (byte)'D', + (byte)'E', + (byte)'F', + }; +#endif + + private enum EncodingContext + { + QueryKey, + QueryValue, + Path, + } + + /// + /// Percent-encodes a path segment value per RFC 3986 section 3.3 (pchar). + /// Allowed unencoded: unreserved / sub-delims / ":" / "@" + /// + public static string EncodePathSegment(string value) + { + if (string.IsNullOrEmpty(value)) + return value; + +#if NET6_0_OR_GREATER + if (!NeedsEncoding(value.AsSpan(), EncodingContext.Path)) + return value; + + var buffer = ArrayPool.Shared.Rent(value.Length * 3); + try + { + var written = EncodeSlow(value.AsSpan(), buffer.AsSpan(), EncodingContext.Path); + return new string(buffer.AsSpan(0, written)); + } + finally + { + ArrayPool.Shared.Return(buffer); + } +#else + var sb = new StringBuilder(value.Length); + AppendEncoded(sb, value, EncodingContext.Path); + return sb.ToString(); +#endif + } + +#if NET6_0_OR_GREATER + /// + /// Builds a query string from the provided parameters. + /// + public static string Build(ReadOnlySpan> parameters) + { + if (parameters.IsEmpty) + return string.Empty; + + var estimatedLength = EstimateLength(parameters); + if (estimatedLength == 0) + return string.Empty; + + var bufferSize = Math.Min(estimatedLength * 3, 8192); + var buffer = ArrayPool.Shared.Rent(bufferSize); + + try + { + var written = BuildCore(parameters, buffer); + return new string(buffer.AsSpan(0, written)); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + + private static int EstimateLength(ReadOnlySpan> parameters) + { + var estimatedLength = 0; + foreach (var kvp in parameters) + { + estimatedLength += kvp.Key.Length + kvp.Value.Length + 2; + } + return estimatedLength; + } +#endif + + /// + /// Builds a query string from the provided parameters. + /// + public static string Build(IEnumerable> parameters) + { +#if NET6_0_OR_GREATER + // Try to get span access for collections that support it + if (parameters is ICollection> collection) + { + if (collection.Count == 0) + return string.Empty; + + var array = ArrayPool>.Shared.Rent(collection.Count); + try + { + collection.CopyTo(array, 0); + return Build(array.AsSpan(0, collection.Count)); + } + finally + { + ArrayPool>.Shared.Return(array); + } + } + + // Fallback for non-collection enumerables + using var enumerator = parameters.GetEnumerator(); + if (!enumerator.MoveNext()) + return string.Empty; + + var buffer = ArrayPool.Shared.Rent(4096); + try + { + var position = 0; + var first = true; + + do + { + var kvp = enumerator.Current; + + // Ensure capacity (worst case: 3x for encoding + separators) + var required = (kvp.Key.Length + kvp.Value.Length + 2) * 3; + if (position + required > buffer.Length) + { + var newBuffer = ArrayPool.Shared.Rent(buffer.Length * 2); + buffer.AsSpan(0, position).CopyTo(newBuffer); + ArrayPool.Shared.Return(buffer); + buffer = newBuffer; + } + + buffer[position++] = first ? '?' : '&'; + first = false; + + position += EncodeWithCharSet( + kvp.Key.AsSpan(), + buffer.AsSpan(position), + EncodingContext.QueryKey + ); + buffer[position++] = '='; + position += EncodeWithCharSet( + kvp.Value.AsSpan(), + buffer.AsSpan(position), + EncodingContext.QueryValue + ); + } while (enumerator.MoveNext()); + + return first ? string.Empty : new string(buffer.AsSpan(0, position)); + } + finally + { + ArrayPool.Shared.Return(buffer); + } +#else + // netstandard2.0 / net462 fallback using StringBuilder + var sb = new StringBuilder(); + var first = true; + + foreach (var kvp in parameters) + { + sb.Append(first ? '?' : '&'); + first = false; + + AppendEncoded(sb, kvp.Key, EncodingContext.QueryKey); + sb.Append('='); + AppendEncoded(sb, kvp.Value, EncodingContext.QueryValue); + } + + return sb.ToString(); +#endif + } + +#if NET6_0_OR_GREATER + private static int BuildCore( + ReadOnlySpan> parameters, + Span buffer + ) + { + var position = 0; + var first = true; + + foreach (var kvp in parameters) + { + buffer[position++] = first ? '?' : '&'; + first = false; + + position += EncodeWithCharSet( + kvp.Key.AsSpan(), + buffer.Slice(position), + EncodingContext.QueryKey + ); + buffer[position++] = '='; + position += EncodeWithCharSet( + kvp.Value.AsSpan(), + buffer.Slice(position), + EncodingContext.QueryValue + ); + } + + return position; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int EncodeWithCharSet( + ReadOnlySpan input, + Span output, + EncodingContext context + ) + { + if (!NeedsEncoding(input, context)) + { + input.CopyTo(output); + return input.Length; + } + + return EncodeSlow(input, output, context); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool NeedsEncoding(ReadOnlySpan value, EncodingContext context) + { + return context switch + { + EncodingContext.QueryKey => value.ContainsAnyExcept(SafeQueryKeyChars), + EncodingContext.QueryValue => value.ContainsAnyExcept(SafeQueryValueChars), + EncodingContext.Path => value.ContainsAnyExcept(SafePathChars), + _ => true, + }; + } + + private static int EncodeSlow( + ReadOnlySpan input, + Span output, + EncodingContext context + ) + { + var position = 0; + + foreach (var c in input) + { + if (IsSafeChar(c, context)) + { + output[position++] = c; + } + else if (c == ' ') + { + output[position++] = '%'; + output[position++] = '2'; + output[position++] = '0'; + } + else if (char.IsAscii(c)) + { + position += EncodeAscii((byte)c, output.Slice(position)); + } + else + { + position += EncodeUtf8(c, output.Slice(position)); + } + } + + return position; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int EncodeAscii(byte value, Span output) + { + output[0] = '%'; + output[1] = (char)UpperHexChars[value >> 4]; + output[2] = (char)UpperHexChars[value & 0xF]; + return 3; + } + + private static int EncodeUtf8(char c, Span output) + { + Span utf8Bytes = stackalloc byte[4]; + Span singleChar = stackalloc char[1] { c }; + var byteCount = global::System.Text.Encoding.UTF8.GetBytes(singleChar, utf8Bytes); + + var position = 0; + for (var i = 0; i < byteCount; i++) + { + output[position++] = '%'; + output[position++] = (char)UpperHexChars[utf8Bytes[i] >> 4]; + output[position++] = (char)UpperHexChars[utf8Bytes[i] & 0xF]; + } + + return position; + } +#else + // netstandard2.0 / net462 StringBuilder-based encoding + private static void AppendEncoded(StringBuilder sb, string value, EncodingContext context) + { + foreach (var c in value) + { + if (IsSafeChar(c, context)) + { + sb.Append(c); + } + else if (c == ' ') + { + sb.Append("%20"); + } + else if (c <= 127) + { + AppendPercentEncoded(sb, (byte)c); + } + else + { + var bytes = Encoding.UTF8.GetBytes(new[] { c }); + foreach (var b in bytes) + { + AppendPercentEncoded(sb, b); + } + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AppendPercentEncoded(StringBuilder sb, byte value) + { + sb.Append('%'); + sb.Append((char)UpperHexChars[value >> 4]); + sb.Append((char)UpperHexChars[value & 0xF]); + } +#endif + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsSafeChar(char c, EncodingContext context) + { + return context switch + { + EncodingContext.QueryKey => IsSafeQueryKeyChar(c), + EncodingContext.QueryValue => IsSafeQueryValueChar(c), + EncodingContext.Path => IsSafePathChar(c), + _ => false, + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsSafeQueryKeyChar(char c) + { +#if NET8_0_OR_GREATER + return SafeQueryKeyChars.Contains(c); +#else + // query = *( pchar / "/" / "?" ) minus "&", "=", "+", ";", "#" + return (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z') + || (c >= '0' && c <= '9') + || c == '-' + || c == '_' + || c == '.' + || c == '~' + || c == '!' + || c == '$' + || c == (char)39 // single quote + || c == '(' + || c == ')' + || c == '*' + || c == ',' + || c == ':' + || c == '@' + || c == '/' + || c == '?'; +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsSafeQueryValueChar(char c) + { +#if NET8_0_OR_GREATER + return SafeQueryValueChars.Contains(c); +#else + // query = *( pchar / "/" / "?" ) minus "&", "+", ";", "#" + return (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z') + || (c >= '0' && c <= '9') + || c == '-' + || c == '_' + || c == '.' + || c == '~' + || c == '!' + || c == '$' + || c == (char)39 // single quote + || c == '(' + || c == ')' + || c == '*' + || c == ',' + || c == '=' + || c == ':' + || c == '@' + || c == '/' + || c == '?'; +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsSafePathChar(char c) + { +#if NET8_0_OR_GREATER + return SafePathChars.Contains(c); +#else + // pchar = unreserved / sub-delims / ":" / "@" + return (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z') + || (c >= '0' && c <= '9') + || c == '-' + || c == '_' + || c == '.' + || c == '~' + || c == '!' + || c == '$' + || c == '&' + || c == (char)39 // single quote + || c == '(' + || c == ')' + || c == '*' + || c == '+' + || c == ',' + || c == ';' + || c == '=' + || c == ':' + || c == '@'; +#endif + } + + /// + /// Fluent builder for constructing query strings with support for simple parameters and deep object notation. + /// + public sealed class Builder + { + private readonly List> _params; + + /// + /// Initializes a new instance with default capacity. + /// + public Builder() + { + _params = new List>(); + } + + /// + /// Initializes a new instance with the specified initial capacity. + /// + public Builder(int capacity) + { + _params = new List>(capacity); + } + + /// + /// Adds a simple parameter. For collections, adds multiple key-value pairs (one per element). + /// + public Builder Add(string key, object? value) + { + if (value is null) + { + return this; + } + + // Handle string separately since it implements IEnumerable + if (value is string stringValue) + { + _params.Add(new KeyValuePair(key, stringValue)); + return this; + } + + // Handle collections (arrays, lists, etc.) - add each element as a separate key-value pair + if ( + value + is global::System.Collections.IEnumerable enumerable + and not global::System.Collections.IDictionary + ) + { + foreach (var item in enumerable) + { + if (item is not null) + { + _params.Add( + new KeyValuePair( + key, + ValueConvert.ToQueryStringValue(item) + ) + ); + } + } + return this; + } + + // Handle scalar values + _params.Add( + new KeyValuePair(key, ValueConvert.ToQueryStringValue(value)) + ); + return this; + } + + /// + /// Sets a parameter, removing any existing parameters with the same key before adding the new value. + /// For collections, removes all existing parameters with the key, then adds multiple key-value pairs (one per element). + /// This allows overriding parameters set earlier in the builder. + /// + public Builder Set(string key, object? value) + { + // Remove all existing parameters with this key + _params.RemoveAll(kv => kv.Key == key); + + // Add the new value(s) + return Add(key, value); + } + + /// + /// Merges additional query parameters with override semantics. + /// Groups parameters by key and calls Set() once per unique key. + /// This ensures that parameters with the same key are properly merged: + /// - If a key appears once, it's added as a single value + /// - If a key appears multiple times, all values are added as an array + /// - All parameters override any existing parameters with the same key + /// + public Builder MergeAdditional( + global::System.Collections.Generic.IEnumerable>? additionalParameters + ) + { + if (additionalParameters is null) + { + return this; + } + + // Group by key to handle multiple values for the same key correctly + var grouped = additionalParameters + .GroupBy(kv => kv.Key) + .Select(g => new global::System.Collections.Generic.KeyValuePair( + g.Key, + g.Count() == 1 ? (object)g.First().Value : g.Select(kv => kv.Value).ToArray() + )); + + foreach (var param in grouped) + { + Set(param.Key, param.Value); + } + + return this; + } + + /// + /// Adds a complex object using deep object notation with a prefix. + /// Deep object notation nests properties with brackets: prefix[key][nested]=value + /// + public Builder AddDeepObject(string prefix, object? value) + { + if (value is not null) + { + _params.AddRange(QueryStringConverter.ToDeepObject(prefix, value)); + } + return this; + } + + /// + /// Adds a complex object using exploded form notation with an optional prefix. + /// Exploded form flattens properties: prefix[key]=value (no deep nesting). + /// + public Builder AddExploded(string prefix, object? value) + { + if (value is not null) + { + _params.AddRange(QueryStringConverter.ToExplodedForm(prefix, value)); + } + return this; + } + + /// + /// Builds the final query string. + /// + public string Build() + { + return QueryStringBuilder.Build(_params); + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/QueryStringConverter.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/QueryStringConverter.cs new file mode 100644 index 000000000000..430cc9ad36c1 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/QueryStringConverter.cs @@ -0,0 +1,259 @@ +using global::System.Text.Json; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Converts an object into a query string collection. +/// +internal static class QueryStringConverter +{ + /// + /// Converts an object into a query string collection using Deep Object notation with a prefix. + /// + /// The prefix to prepend to all keys (e.g., "session_settings"). Pass empty string for no prefix. + /// Object to form URL-encode. Can be an object, array of objects, or dictionary. + /// Throws when passing in a string or primitive value. + /// A collection of key value pairs. The keys and values are not URL encoded. + internal static IEnumerable> ToDeepObject( + string prefix, + object value + ) + { + var queryCollection = new List>(); + var json = JsonUtils.SerializeToElement(value); + JsonToDeepObject(json, prefix, queryCollection); + return queryCollection; + } + + /// + /// Converts an object into a query string collection using Deep Object notation. + /// + /// Object to form URL-encode. Can be an object, array of objects, or dictionary. + /// Throws when passing in a string or primitive value. + /// A collection of key value pairs. The keys and values are not URL encoded. + internal static IEnumerable> ToDeepObject(object value) + { + return ToDeepObject("", value); + } + + /// + /// Converts an object into a query string collection using Exploded Form notation with a prefix. + /// + /// The prefix to prepend to all keys. Pass empty string for no prefix. + /// Object to form URL-encode. You can pass in an object or dictionary, but not lists, strings, or primitives. + /// Throws when passing in a list, a string, or a primitive value. + /// A collection of key value pairs. The keys and values are not URL encoded. + internal static IEnumerable> ToExplodedForm( + string prefix, + object value + ) + { + var queryCollection = new List>(); + var json = JsonUtils.SerializeToElement(value); + AssertRootJson(json); + JsonToFormExploded(json, prefix, queryCollection); + return queryCollection; + } + + /// + /// Converts an object into a query string collection using Exploded Form notation. + /// + /// Object to form URL-encode. You can pass in an object or dictionary, but not lists, strings, or primitives. + /// Throws when passing in a list, a string, or a primitive value. + /// A collection of key value pairs. The keys and values are not URL encoded. + internal static IEnumerable> ToExplodedForm(object value) + { + return ToExplodedForm("", value); + } + + /// + /// Converts an object into a query string collection using Form notation without exploding parameters. + /// + /// Object to form URL-encode. You can pass in an object or dictionary, but not lists, strings, or primitives. + /// Throws when passing in a list, a string, or a primitive value. + /// A collection of key value pairs. The keys and values are not URL encoded. + internal static IEnumerable> ToForm(object value) + { + var queryCollection = new List>(); + var json = JsonUtils.SerializeToElement(value); + AssertRootJson(json); + JsonToForm(json, "", queryCollection); + return queryCollection; + } + + private static void AssertRootJson(JsonElement json) + { + switch (json.ValueKind) + { + case JsonValueKind.Object: + break; + case JsonValueKind.Array: + case JsonValueKind.Undefined: + case JsonValueKind.String: + case JsonValueKind.Number: + case JsonValueKind.True: + case JsonValueKind.False: + case JsonValueKind.Null: + default: + throw new global::System.Exception( + $"Only objects can be converted to query string collections. Given type is {json.ValueKind}." + ); + } + } + + private static void JsonToForm( + JsonElement element, + string prefix, + List> parameters + ) + { + switch (element.ValueKind) + { + case JsonValueKind.Object: + foreach (var property in element.EnumerateObject()) + { + var newPrefix = string.IsNullOrEmpty(prefix) + ? property.Name + : $"{prefix}[{property.Name}]"; + + JsonToForm(property.Value, newPrefix, parameters); + } + break; + case JsonValueKind.Array: + var arrayValues = element.EnumerateArray().Select(ValueToString).ToArray(); + parameters.Add( + new KeyValuePair(prefix, string.Join(",", arrayValues)) + ); + break; + case JsonValueKind.Null: + break; + case JsonValueKind.Undefined: + case JsonValueKind.String: + case JsonValueKind.Number: + case JsonValueKind.True: + case JsonValueKind.False: + default: + parameters.Add(new KeyValuePair(prefix, ValueToString(element))); + break; + } + } + + private static void JsonToFormExploded( + JsonElement element, + string prefix, + List> parameters + ) + { + switch (element.ValueKind) + { + case JsonValueKind.Object: + foreach (var property in element.EnumerateObject()) + { + var newPrefix = string.IsNullOrEmpty(prefix) + ? property.Name + : $"{prefix}[{property.Name}]"; + + JsonToFormExploded(property.Value, newPrefix, parameters); + } + + break; + case JsonValueKind.Array: + foreach (var item in element.EnumerateArray()) + { + if ( + item.ValueKind != JsonValueKind.Object + && item.ValueKind != JsonValueKind.Array + ) + { + parameters.Add( + new KeyValuePair(prefix, ValueToString(item)) + ); + } + else + { + JsonToFormExploded(item, prefix, parameters); + } + } + + break; + case JsonValueKind.Null: + break; + case JsonValueKind.Undefined: + case JsonValueKind.String: + case JsonValueKind.Number: + case JsonValueKind.True: + case JsonValueKind.False: + default: + parameters.Add(new KeyValuePair(prefix, ValueToString(element))); + break; + } + } + + private static void JsonToDeepObject( + JsonElement element, + string prefix, + List> parameters + ) + { + switch (element.ValueKind) + { + case JsonValueKind.Object: + foreach (var property in element.EnumerateObject()) + { + var newPrefix = string.IsNullOrEmpty(prefix) + ? property.Name + : $"{prefix}[{property.Name}]"; + + JsonToDeepObject(property.Value, newPrefix, parameters); + } + + break; + case JsonValueKind.Array: + var index = 0; + foreach (var item in element.EnumerateArray()) + { + var newPrefix = $"{prefix}[{index++}]"; + + if ( + item.ValueKind != JsonValueKind.Object + && item.ValueKind != JsonValueKind.Array + ) + { + parameters.Add( + new KeyValuePair(newPrefix, ValueToString(item)) + ); + } + else + { + JsonToDeepObject(item, newPrefix, parameters); + } + } + + break; + case JsonValueKind.Null: + case JsonValueKind.Undefined: + // Skip null and undefined values - don't add parameters for them + break; + case JsonValueKind.String: + case JsonValueKind.Number: + case JsonValueKind.True: + case JsonValueKind.False: + default: + parameters.Add(new KeyValuePair(prefix, ValueToString(element))); + break; + } + } + + private static string ValueToString(JsonElement element) + { + return element.ValueKind switch + { + JsonValueKind.String => element.GetString() ?? "", + JsonValueKind.Number => element.GetRawText(), + JsonValueKind.True => "true", + JsonValueKind.False => "false", + JsonValueKind.Null => "", + _ => element.GetRawText(), + }; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/RawClient.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/RawClient.cs new file mode 100644 index 000000000000..222916404413 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/RawClient.cs @@ -0,0 +1,364 @@ +using global::System.Net.Http; +using global::System.Net.Http.Headers; +using global::System.Text; +using SystemTask = global::System.Threading.Tasks.Task; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Utility class for making raw HTTP requests to the API. +/// +internal partial class RawClient(ClientOptions clientOptions) +{ + private const int MaxRetryDelayMs = 60000; + private const double JitterFactor = 0.2; +#if NET6_0_OR_GREATER + // Use Random.Shared for thread-safe random number generation on .NET 6+ +#else + private static readonly object JitterLock = new(); + private static readonly Random JitterRandom = new(); +#endif + internal int BaseRetryDelay { get; set; } = 1000; + + /// + /// The client options applied on every request. + /// + internal readonly ClientOptions Options = clientOptions; + + internal async global::System.Threading.Tasks.Task SendRequestAsync( + global::SeedCsharpXmlEntities.Core.BaseRequest request, + CancellationToken cancellationToken = default + ) + { + // Apply the request timeout. + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + var timeout = request.Options?.Timeout ?? Options.Timeout; + cts.CancelAfter(timeout); + + var httpRequest = await CreateHttpRequestAsync(request).ConfigureAwait(false); + // Send the request. + return await SendWithRetriesAsync(httpRequest, request.Options, cts.Token) + .ConfigureAwait(false); + } + + internal async global::System.Threading.Tasks.Task SendRequestAsync( + HttpRequestMessage request, + IRequestOptions? options, + CancellationToken cancellationToken = default + ) + { + // Apply the request timeout. + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + var timeout = options?.Timeout ?? Options.Timeout; + cts.CancelAfter(timeout); + + // Send the request. + return await SendWithRetriesAsync(request, options, cts.Token).ConfigureAwait(false); + } + + private static async global::System.Threading.Tasks.Task CloneRequestAsync( + HttpRequestMessage request, + CancellationToken cancellationToken = default + ) + { + var clonedRequest = new HttpRequestMessage(request.Method, request.RequestUri); + clonedRequest.Version = request.Version; + + if (request.Content != null) + { + switch (request.Content) + { + case MultipartContent oldMultipartFormContent: + var originalBoundary = + oldMultipartFormContent + .Headers.ContentType?.Parameters.First(p => + p.Name.Equals("boundary", StringComparison.OrdinalIgnoreCase) + ) + .Value?.Trim('"') + ?? Guid.NewGuid().ToString(); + var newMultipartContent = oldMultipartFormContent switch + { + MultipartFormDataContent => new MultipartFormDataContent(originalBoundary), + _ => new MultipartContent(), + }; + foreach (var content in oldMultipartFormContent) + { + var ms = new MemoryStream(); +#if NET5_0_OR_GREATER + await content.CopyToAsync(ms, cancellationToken).ConfigureAwait(false); +#else + await content.CopyToAsync(ms).ConfigureAwait(false); +#endif + ms.Position = 0; + var newPart = new StreamContent(ms); + foreach (var header in content.Headers) + { + newPart.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + + newMultipartContent.Add(newPart); + } + + clonedRequest.Content = newMultipartContent; + break; + default: + var bodyStream = new MemoryStream(); +#if NET5_0_OR_GREATER + await request + .Content.CopyToAsync(bodyStream, cancellationToken) + .ConfigureAwait(false); +#else + await request.Content.CopyToAsync(bodyStream).ConfigureAwait(false); +#endif + bodyStream.Position = 0; + var clonedContent = new StreamContent(bodyStream); + foreach (var header in request.Content.Headers) + { + clonedContent.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + + clonedRequest.Content = clonedContent; + break; + } + } + + foreach (var header in request.Headers) + { + clonedRequest.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + + return clonedRequest; + } + + /// + /// Sends the request with retries, unless the request content is not retryable, + /// such as stream requests and multipart form data with stream content. + /// + private async global::System.Threading.Tasks.Task SendWithRetriesAsync( + HttpRequestMessage request, + IRequestOptions? options, + CancellationToken cancellationToken + ) + { + var httpClient = options?.HttpClient ?? Options.HttpClient; + var maxRetries = Math.Max(0, options?.MaxRetries ?? Options.MaxRetries); + var isRetryableContent = IsRetryableContent(request); + + if (!isRetryableContent || maxRetries == 0) + { + var response = await httpClient + .SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken) + .ConfigureAwait(false); + return new global::SeedCsharpXmlEntities.Core.ApiResponse + { + StatusCode = (int)response.StatusCode, + Raw = response, + }; + } + + // Always send a clone, never the original: HttpClient (e.g. under HTTP/2) disposes + // request.Content after sending, which would break the next attempt's clone. + HttpResponseMessage? retryResponse = null; + for (var attempt = 0; attempt <= maxRetries; attempt++) + { + if (attempt > 0) + { + var delayMs = GetRetryDelayFromHeaders(retryResponse!, attempt - 1); + await SystemTask.Delay(delayMs, cancellationToken).ConfigureAwait(false); + } + + using var attemptRequest = await CloneRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + retryResponse = await httpClient + .SendAsync( + attemptRequest, + HttpCompletionOption.ResponseHeadersRead, + cancellationToken + ) + .ConfigureAwait(false); + + if (!ShouldRetry(retryResponse)) + { + break; + } + } + + return new global::SeedCsharpXmlEntities.Core.ApiResponse + { + StatusCode = (int)retryResponse!.StatusCode, + Raw = retryResponse, + }; + } + + private static bool ShouldRetry(HttpResponseMessage response) + { + var statusCode = (int)response.StatusCode; + + return statusCode is 408 or 429 or (>= 500); + } + + private static int AddPositiveJitter(int delayMs) + { +#if NET6_0_OR_GREATER + var random = Random.Shared.NextDouble(); +#else + double random; + lock (JitterLock) + { + random = JitterRandom.NextDouble(); + } +#endif + var jitterMultiplier = 1 + random * JitterFactor; + return (int)(delayMs * jitterMultiplier); + } + + private static int AddSymmetricJitter(int delayMs) + { +#if NET6_0_OR_GREATER + var random = Random.Shared.NextDouble(); +#else + double random; + lock (JitterLock) + { + random = JitterRandom.NextDouble(); + } +#endif + var jitterMultiplier = 1 + (random - 0.5) * JitterFactor; + return (int)(delayMs * jitterMultiplier); + } + + private int GetRetryDelayFromHeaders(HttpResponseMessage response, int retryAttempt) + { + if (response.Headers.TryGetValues("Retry-After", out var retryAfterValues)) + { + var retryAfter = retryAfterValues.FirstOrDefault(); + if (!string.IsNullOrEmpty(retryAfter)) + { + if (int.TryParse(retryAfter, out var retryAfterSeconds) && retryAfterSeconds > 0) + { + return Math.Min(retryAfterSeconds * 1000, MaxRetryDelayMs); + } + + if (DateTimeOffset.TryParse(retryAfter, out var retryAfterDate)) + { + var delay = (int)(retryAfterDate - DateTimeOffset.UtcNow).TotalMilliseconds; + if (delay > 0) + { + return Math.Min(delay, MaxRetryDelayMs); + } + } + } + } + + if (response.Headers.TryGetValues("X-RateLimit-Reset", out var rateLimitResetValues)) + { + var rateLimitReset = rateLimitResetValues.FirstOrDefault(); + if ( + !string.IsNullOrEmpty(rateLimitReset) + && long.TryParse(rateLimitReset, out var resetTime) + ) + { + var resetDateTime = DateTimeOffset.FromUnixTimeSeconds(resetTime); + var delay = (int)(resetDateTime - DateTimeOffset.UtcNow).TotalMilliseconds; + if (delay > 0) + { + return AddPositiveJitter(Math.Min(delay, MaxRetryDelayMs)); + } + } + } + + var exponentialDelay = Math.Min(BaseRetryDelay * (1 << retryAttempt), MaxRetryDelayMs); + return AddSymmetricJitter(exponentialDelay); + } + + private static bool IsRetryableContent(HttpRequestMessage request) + { + return request.Content switch + { + IIsRetryableContent c => c.IsRetryable, + StreamContent => false, + MultipartContent content => !content.Any(c => c is StreamContent), + _ => true, + }; + } + + internal async global::System.Threading.Tasks.Task CreateHttpRequestAsync( + global::SeedCsharpXmlEntities.Core.BaseRequest request + ) + { + var url = BuildUrl(request); + var httpRequest = new HttpRequestMessage(request.Method, url); + httpRequest.Content = request.CreateContent(); + SetHeaders(httpRequest, request.Headers); + + return httpRequest; + } + + private string BuildUrl(global::SeedCsharpXmlEntities.Core.BaseRequest request) + { + var baseUrl = request.Options?.BaseUrl ?? request.BaseUrl ?? Options.BaseUrl; + + var trimmedBaseUrl = baseUrl.TrimEnd('/'); + var trimmedBasePath = request.Path.TrimStart('/'); + var url = $"{trimmedBaseUrl}/{trimmedBasePath}"; + + // Append query string if present + if (!string.IsNullOrEmpty(request.QueryString)) + { + return url + request.QueryString; + } + + return url; + } + + private void SetHeaders(HttpRequestMessage httpRequest, Dictionary? headers) + { + if (headers is null) + { + return; + } + + foreach (var kv in headers) + { + if (kv.Value is null) + { + continue; + } + + httpRequest.Headers.TryAddWithoutValidation(kv.Key, kv.Value); + } + } + + private static (Encoding encoding, string? charset, string mediaType) ParseContentTypeOrDefault( + string? contentType, + Encoding encodingFallback, + string mediaTypeFallback + ) + { + var encoding = encodingFallback; + var mediaType = mediaTypeFallback; + string? charset = null; + if (string.IsNullOrEmpty(contentType)) + { + return (encoding, charset, mediaType); + } + + if (!MediaTypeHeaderValue.TryParse(contentType, out var mediaTypeHeaderValue)) + { + return (encoding, charset, mediaType); + } + + if (!string.IsNullOrEmpty(mediaTypeHeaderValue.CharSet)) + { + charset = mediaTypeHeaderValue.CharSet; + encoding = Encoding.GetEncoding(mediaTypeHeaderValue.CharSet); + } + + if (!string.IsNullOrEmpty(mediaTypeHeaderValue.MediaType)) + { + mediaType = mediaTypeHeaderValue.MediaType; + } + + return (encoding, charset, mediaType); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/RawResponse.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/RawResponse.cs new file mode 100644 index 000000000000..bf244dc3c39e --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/RawResponse.cs @@ -0,0 +1,24 @@ +using global::System.Net; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Contains HTTP response metadata including status code, URL, and headers. +/// +public record RawResponse +{ + /// + /// The HTTP status code of the response. + /// + public required HttpStatusCode StatusCode { get; init; } + + /// + /// The request URL that generated this response. + /// + public required Uri Url { get; init; } + + /// + /// The HTTP response headers. + /// + public required Core.ResponseHeaders Headers { get; init; } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/ResponseHeaders.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/ResponseHeaders.cs new file mode 100644 index 000000000000..dc8e31f168ff --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/ResponseHeaders.cs @@ -0,0 +1,108 @@ +using global::System.Collections; +using global::System.Net.Http.Headers; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Represents HTTP response headers with case-insensitive lookup. +/// +public readonly struct ResponseHeaders : IEnumerable +{ + private readonly HttpResponseHeaders? _headers; + private readonly HttpContentHeaders? _contentHeaders; + + private ResponseHeaders(HttpResponseHeaders headers, HttpContentHeaders? contentHeaders) + { + _headers = headers; + _contentHeaders = contentHeaders; + } + + /// + /// Gets the Content-Type header value, if present. + /// + public string? ContentType => _contentHeaders?.ContentType?.ToString(); + + /// + /// Gets the Content-Length header value, if present. + /// + public long? ContentLength => _contentHeaders?.ContentLength; + + /// + /// Creates a ResponseHeaders instance from an HttpResponseMessage. + /// + public static ResponseHeaders FromHttpResponseMessage(HttpResponseMessage response) + { + return new ResponseHeaders(response.Headers, response.Content?.Headers); + } + + /// + /// Tries to get a single header value. Returns the first value if multiple values exist. + /// + public bool TryGetValue(string name, out string? value) + { + if (TryGetValues(name, out var values) && values is not null) + { + value = values.FirstOrDefault(); + return true; + } + + value = null; + return false; + } + + /// + /// Tries to get all values for a header. + /// + public bool TryGetValues(string name, out IEnumerable? values) + { + if (_headers?.TryGetValues(name, out values) == true) + { + return true; + } + + if (_contentHeaders?.TryGetValues(name, out values) == true) + { + return true; + } + + values = null; + return false; + } + + /// + /// Checks if the headers contain a specific header name. + /// + public bool Contains(string name) + { + return _headers?.Contains(name) == true || _contentHeaders?.Contains(name) == true; + } + + /// + /// Gets an enumerator for all headers. + /// + public IEnumerator GetEnumerator() + { + if (_headers is not null) + { + foreach (var header in _headers) + { + yield return new HttpHeader(header.Key, string.Join(", ", header.Value)); + } + } + + if (_contentHeaders is not null) + { + foreach (var header in _contentHeaders) + { + yield return new HttpHeader(header.Key, string.Join(", ", header.Value)); + } + } + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} + +/// +/// Represents a single HTTP header. +/// +public readonly record struct HttpHeader(string Name, string Value); diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/StreamRequest.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/StreamRequest.cs new file mode 100644 index 000000000000..029f1a9ceedd --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/StreamRequest.cs @@ -0,0 +1,29 @@ +using global::System.Net.Http; +using global::System.Net.Http.Headers; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// The request object to be sent for streaming uploads. +/// +internal record StreamRequest : BaseRequest +{ + internal Stream? Body { get; init; } + + internal override HttpContent? CreateContent() + { + if (Body is null) + { + return null; + } + + var content = new StreamContent(Body) + { + Headers = + { + ContentType = MediaTypeHeaderValue.Parse(ContentType ?? "application/octet-stream"), + }, + }; + return content; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/StringEnum.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/StringEnum.cs new file mode 100644 index 000000000000..1c3dfea3287b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/StringEnum.cs @@ -0,0 +1,6 @@ +namespace SeedCsharpXmlEntities.Core; + +public interface IStringEnum : IEquatable +{ + public string Value { get; } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/StringEnumExtensions.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/StringEnumExtensions.cs new file mode 100644 index 000000000000..1882c6dd461e --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/StringEnumExtensions.cs @@ -0,0 +1,6 @@ +namespace SeedCsharpXmlEntities.Core; + +internal static class StringEnumExtensions +{ + public static string Stringify(this IStringEnum stringEnum) => stringEnum.Value; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/ValueConvert.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/ValueConvert.cs new file mode 100644 index 000000000000..d39f1360b663 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Core/ValueConvert.cs @@ -0,0 +1,115 @@ +using global::System.Globalization; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Convert values to string for path and query parameters. +/// +public static class ValueConvert +{ + internal static string ToPathParameterString(T value) => ToString(value); + + internal static string ToPathParameterString(bool v) => ToString(v); + + internal static string ToPathParameterString(int v) => ToString(v); + + internal static string ToPathParameterString(long v) => ToString(v); + + internal static string ToPathParameterString(float v) => ToString(v); + + internal static string ToPathParameterString(double v) => ToString(v); + + internal static string ToPathParameterString(decimal v) => ToString(v); + + internal static string ToPathParameterString(short v) => ToString(v); + + internal static string ToPathParameterString(ushort v) => ToString(v); + + internal static string ToPathParameterString(uint v) => ToString(v); + + internal static string ToPathParameterString(ulong v) => ToString(v); + + internal static string ToPathParameterString(string v) => + QueryStringBuilder.EncodePathSegment(v); + + internal static string ToPathParameterString(char v) => ToString(v); + + internal static string ToPathParameterString(Guid v) => ToString(v); + + internal static string ToQueryStringValue(T value) => value is null ? "" : ToString(value); + + internal static string ToQueryStringValue(bool v) => ToString(v); + + internal static string ToQueryStringValue(int v) => ToString(v); + + internal static string ToQueryStringValue(long v) => ToString(v); + + internal static string ToQueryStringValue(float v) => ToString(v); + + internal static string ToQueryStringValue(double v) => ToString(v); + + internal static string ToQueryStringValue(decimal v) => ToString(v); + + internal static string ToQueryStringValue(short v) => ToString(v); + + internal static string ToQueryStringValue(ushort v) => ToString(v); + + internal static string ToQueryStringValue(uint v) => ToString(v); + + internal static string ToQueryStringValue(ulong v) => ToString(v); + + internal static string ToQueryStringValue(string v) => v is null ? "" : v; + + internal static string ToQueryStringValue(char v) => ToString(v); + + internal static string ToQueryStringValue(Guid v) => ToString(v); + + internal static string ToString(T value) + { + return value switch + { + null => "null", + string str => str, + true => "true", + false => "false", + int i => ToString(i), + long l => ToString(l), + float f => ToString(f), + double d => ToString(d), + decimal dec => ToString(dec), + short s => ToString(s), + ushort u => ToString(u), + uint u => ToString(u), + ulong u => ToString(u), + char c => ToString(c), + Guid guid => ToString(guid), + _ => JsonUtils.SerializeRelaxedEscaping(value, value.GetType()).Trim('"'), + }; + } + + internal static string ToString(bool v) => v ? "true" : "false"; + + internal static string ToString(int v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(long v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(float v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(double v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(decimal v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(short v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(ushort v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(uint v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(ulong v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(char v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(string v) => v; + + internal static string ToString(Guid v) => v.ToString("D"); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/ISeedCsharpXmlEntitiesClient.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/ISeedCsharpXmlEntitiesClient.cs new file mode 100644 index 000000000000..0810efe8d947 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/ISeedCsharpXmlEntitiesClient.cs @@ -0,0 +1,12 @@ +namespace SeedCsharpXmlEntities; + +public partial interface ISeedCsharpXmlEntitiesClient +{ + /// + /// Get timezone information with + offset + /// + WithRawResponseTask GetTimeZoneAsync( + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.Custom.props b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.Custom.props new file mode 100644 index 000000000000..17a84cada530 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.Custom.props @@ -0,0 +1,20 @@ + + + + diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj new file mode 100644 index 000000000000..cf0d75095f0e --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj @@ -0,0 +1,70 @@ + + + net462;net8.0;net9.0;netstandard2.0 + enable + 12 + enable + 0.0.1 + $(Version) + $(Version) + README.md + https://github.com/csharp-xml-entities/fern + https://github.com/csharp-xml-entities/fern + git + true + + + + false + + + $(DefineConstants);USE_PORTABLE_DATE_ONLY + true + + + + + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + + + <_Parameter1>SeedCsharpXmlEntities.Test + + + + + diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/SeedCsharpXmlEntitiesClient.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/SeedCsharpXmlEntitiesClient.cs new file mode 100644 index 000000000000..dcdfb1038d52 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/SeedCsharpXmlEntitiesClient.cs @@ -0,0 +1,127 @@ +using global::System.Text.Json; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities; + +public partial class SeedCsharpXmlEntitiesClient : ISeedCsharpXmlEntitiesClient +{ + private readonly RawClient _client; + + public SeedCsharpXmlEntitiesClient(ClientOptions? clientOptions = null) + { + clientOptions ??= new ClientOptions(); + var platformHeaders = new Headers( + new Dictionary() + { + { "X-Fern-Language", "C#" }, + { "X-Fern-SDK-Name", "SeedCsharpXmlEntities" }, + { "X-Fern-SDK-Version", global::SeedCsharpXmlEntities.Version.Current }, + { "User-Agent", "Ferncsharp-xml-entities/0.0.1" }, + } + ); + foreach (var header in platformHeaders) + { + if (!clientOptions.Headers.ContainsKey(header.Key)) + { + clientOptions.Headers[header.Key] = header.Value; + } + } + _client = new RawClient(clientOptions); + } + + private async Task> GetTimeZoneAsyncCore( + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _queryString = new SeedCsharpXmlEntities.Core.QueryStringBuilder.Builder(capacity: 0) + .MergeAdditional(options?.AdditionalQueryParameters) + .Build(); + var _headers = await new SeedCsharpXmlEntities.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethod.Get, + Path = "/timezone", + QueryString = _queryString, + Headers = _headers, + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + var responseData = JsonUtils.Deserialize(responseBody)!; + return new WithRawResponse() + { + Data = responseData, + RawResponse = new SeedCsharpXmlEntities.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }, + }; + } + catch (JsonException e) + { + throw new SeedCsharpXmlEntitiesApiException( + "Failed to deserialize response", + response.StatusCode, + responseBody, + e, + rawResponse: new SeedCsharpXmlEntities.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + throw new SeedCsharpXmlEntitiesApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody, + rawResponse: new SeedCsharpXmlEntities.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + + /// + /// Get timezone information with + offset + /// + /// + /// await client.GetTimeZoneAsync(); + /// + public WithRawResponseTask GetTimeZoneAsync( + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask( + GetTimeZoneAsyncCore(options, cancellationToken) + ); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Types/TimeZoneModel.cs b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Types/TimeZoneModel.cs new file mode 100644 index 000000000000..c1a59a67ff35 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/no-documentation-file/src/SeedCsharpXmlEntities/Types/TimeZoneModel.cs @@ -0,0 +1,65 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities; + +/// +/// Model demonstrating HTML entity bug in C# XML documentation. +/// This description contains HTML entities that are not valid in XML. +/// +[Serializable] +public record TimeZoneModel : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + /// + /// Format is UTC + offset notation (e.g., +05:30) + /// + [JsonPropertyName("timeZoneOffset")] + public required string TimeZoneOffset { get; set; } + + /// + /// Expression: A + B - C × D ÷ E + /// + [JsonPropertyName("mathExpression")] + public required string MathExpression { get; set; } + + /// + /// This uses valid XML entity: A < B & C > D + /// + [JsonPropertyName("validEntity")] + public required string ValidEntity { get; set; } + + /// + /// Special characters: … · © + /// + [JsonPropertyName("specialChars")] + public string? SpecialChars { get; set; } + + /// + /// See see here for details + /// + [JsonPropertyName("documentationLink")] + public string? DocumentationLink { get; set; } + + /// + /// See see here for details + /// + [JsonPropertyName("escapedDocumentationLink")] + public string? EscapedDocumentationLink { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/.editorconfig b/seed/csharp-sdk/csharp-xml-entities/package-metadata/.editorconfig new file mode 100644 index 000000000000..1e7a0adbac80 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/.editorconfig @@ -0,0 +1,35 @@ +root = true + +[*.cs] +resharper_arrange_object_creation_when_type_evident_highlighting = hint +resharper_auto_property_can_be_made_get_only_global_highlighting = hint +resharper_check_namespace_highlighting = hint +resharper_class_never_instantiated_global_highlighting = hint +resharper_class_never_instantiated_local_highlighting = hint +resharper_collection_never_updated_global_highlighting = hint +resharper_convert_type_check_pattern_to_null_check_highlighting = hint +resharper_inconsistent_naming_highlighting = hint +resharper_member_can_be_private_global_highlighting = hint +resharper_member_hides_static_from_outer_class_highlighting = hint +resharper_not_accessed_field_local_highlighting = hint +resharper_nullable_warning_suppression_is_used_highlighting = suggestion +resharper_partial_type_with_single_part_highlighting = hint +resharper_prefer_concrete_value_over_default_highlighting = none +resharper_private_field_can_be_converted_to_local_variable_highlighting = hint +resharper_property_can_be_made_init_only_global_highlighting = hint +resharper_property_can_be_made_init_only_local_highlighting = hint +resharper_redundant_name_qualifier_highlighting = none +resharper_redundant_using_directive_highlighting = hint +resharper_replace_slice_with_range_indexer_highlighting = none +resharper_unused_auto_property_accessor_global_highlighting = hint +resharper_unused_auto_property_accessor_local_highlighting = hint +resharper_unused_member_global_highlighting = hint +resharper_unused_type_global_highlighting = hint +resharper_use_string_interpolation_highlighting = hint +dotnet_diagnostic.CS1591.severity = suggestion + +[src/**/Types/*.cs] +resharper_check_namespace_highlighting = none + +[src/**/Core/Public/*.cs] +resharper_check_namespace_highlighting = none \ No newline at end of file diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/.fern/metadata.json b/seed/csharp-sdk/csharp-xml-entities/package-metadata/.fern/metadata.json new file mode 100644 index 000000000000..ce44b5ebdc33 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/.fern/metadata.json @@ -0,0 +1,27 @@ +{ + "cliVersion": "DUMMY", + "generatorName": "fernapi/fern-csharp-sdk", + "generatorVersion": "local", + "generatorConfig": { + "package-metadata": { + "description": "An SDK for the XML entities API.", + "authors": [ + "Fern", + "Acme" + ], + "tags": [ + "acme", + "sdk" + ], + "copyright": "Copyright (c) Acme, Inc. ", + "project-url": "https://example.com/docs", + "repository-url": "https://github.com/acme/acme-dotnet", + "include-source-link": true, + "include-symbols": true + } + }, + "originGitCommit": "DUMMY", + "invokedBy": "manual", + "requestedVersion": "0.0.1", + "sdkVersion": "0.0.1" +} \ No newline at end of file diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/.github/workflows/ci.yml b/seed/csharp-sdk/csharp-xml-entities/package-metadata/.github/workflows/ci.yml new file mode 100644 index 000000000000..162400395053 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/.github/workflows/ci.yml @@ -0,0 +1,51 @@ +name: ci + +on: [push] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +env: + DOTNET_NOLOGO: true + +jobs: + ci: + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v6 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.x + + - name: Install tools + run: dotnet tool restore + + - name: Restore dependencies + run: dotnet restore src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj + + - name: Build + run: dotnet build src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj --no-restore -c Release + + - name: Restore test dependencies + run: dotnet restore src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj + + - name: Build tests + run: dotnet build src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj --no-restore -c Release + + - name: Test + run: dotnet test src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj --no-restore --no-build -c Release + + - name: Pack + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + run: dotnet pack src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj --no-build --no-restore -c Release + + - name: Publish to NuGet.org + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_TOKEN }} + run: dotnet nuget push src/SeedCsharpXmlEntities/bin/Release/*.nupkg --api-key $NUGET_API_KEY --source "nuget.org" diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/.gitignore b/seed/csharp-sdk/csharp-xml-entities/package-metadata/.gitignore new file mode 100644 index 000000000000..11014f2b33d7 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/.gitignore @@ -0,0 +1,484 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +## This is based on `dotnet new gitignore` and customized by Fern + +# dotenv files +.env + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +# [Rr]elease/ (Ignored by Fern) +# [Rr]eleases/ (Ignored by Fern) +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +# [Ll]og/ (Ignored by Fern) +# [Ll]ogs/ (Ignored by Fern) + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/CONTRIBUTING.md b/seed/csharp-sdk/csharp-xml-entities/package-metadata/CONTRIBUTING.md new file mode 100644 index 000000000000..1de047696582 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/CONTRIBUTING.md @@ -0,0 +1,119 @@ +# Contributing + +Thanks for your interest in contributing to this SDK! This document provides guidelines for contributing to the project. + +## Getting Started + +### Prerequisites + +- .NET SDK (version compatible with the target frameworks: net462, net8.0, netstandard2.0) + +### Installation + +Install the project dependencies: + +```bash +dotnet restore +``` + +### Building + +Build the project: + +```bash +dotnet build +``` + +### Testing + +Run the test suite: + +```bash +dotnet test +``` + +### Formatting + +Check code style: + +```bash +dotnet format --verify-no-changes +``` + +Fix code style issues: + +```bash +dotnet format +``` + +## About Generated Code + +**Important**: Most files in this SDK are automatically generated by [Fern](https://buildwithfern.com) from the API definition. Direct modifications to generated files will be overwritten the next time the SDK is generated. + +### Generated Files + +The following directories contain generated code: +- `src/` - API client classes and types +- Most C# files in the project + +### How to Customize + +If you need to customize the SDK, you have two options: + +#### Option 1: Use `.fernignore` + +For custom code that should persist across SDK regenerations: + +1. Create a `.fernignore` file in the project root +2. Add file patterns for files you want to preserve (similar to `.gitignore` syntax) +3. Add your custom code to those files + +Files listed in `.fernignore` will not be overwritten when the SDK is regenerated. + +For more information, see the [Fern documentation on custom code](https://buildwithfern.com/learn/sdks/overview/custom-code). + +#### Option 2: Contribute to the Generator + +If you want to change how code is generated for all users of this SDK: + +1. The C# SDK generator lives in the [Fern repository](https://github.com/fern-api/fern) +2. Generator code is located at `generators/csharp/` +3. Follow the [Fern contributing guidelines](https://github.com/fern-api/fern/blob/main/CONTRIBUTING.md) +4. Submit a pull request with your changes to the generator + +This approach is best for: +- Bug fixes in generated code +- New features that would benefit all users +- Improvements to code generation patterns + +## Making Changes + +### Workflow + +1. Create a new branch for your changes +2. Make your modifications +3. Run tests to ensure nothing breaks: `dotnet test` +4. Run formatting: `dotnet format` +5. Build the project: `dotnet build` +6. Commit your changes with a clear commit message +7. Push your branch and create a pull request + +### Commit Messages + +Write clear, descriptive commit messages that explain what changed and why. + +### Code Style + +This project uses automated code formatting. Run `dotnet format` before committing to ensure your code meets the project's style guidelines. + +## Questions or Issues? + +If you have questions or run into issues: + +1. Check the [Fern documentation](https://buildwithfern.com) +2. Search existing [GitHub issues](https://github.com/fern-api/fern/issues) +3. Open a new issue if your question hasn't been addressed + +## License + +By contributing to this project, you agree that your contributions will be licensed under the same license as the project. diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/README.md b/seed/csharp-sdk/csharp-xml-entities/package-metadata/README.md new file mode 100644 index 000000000000..271b5329326b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/README.md @@ -0,0 +1,213 @@ +# Seed C# Library + +[![fern shield](https://img.shields.io/badge/%F0%9F%8C%BF-Built%20with%20Fern-brightgreen)](https://buildwithfern.com?utm_source=github&utm_medium=github&utm_campaign=readme&utm_source=Seed%2FC%23) +[![nuget shield](https://img.shields.io/nuget/v/Ferncsharp-xml-entities)](https://nuget.org/packages/Ferncsharp-xml-entities) + +The Seed C# library provides convenient access to the Seed APIs from C#. + +## Table of Contents + +- [Requirements](#requirements) +- [Installation](#installation) +- [Reference](#reference) +- [Usage](#usage) +- [Exception Handling](#exception-handling) +- [Advanced](#advanced) + - [Retries](#retries) + - [Timeouts](#timeouts) + - [Raw Response](#raw-response) + - [Additional Headers](#additional-headers) + - [Additional Query Parameters](#additional-query-parameters) + - [Additional Body Properties](#additional-body-properties) +- [Contributing](#contributing) + +## Requirements + +This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above + +## Installation + +```sh +dotnet add package Ferncsharp-xml-entities +``` + +## Reference + +A full reference for this library is available [here](./reference.md). + +## Usage + +Instantiate and use the client with the following: + +```csharp +using SeedCsharpXmlEntities; + +var client = new SeedCsharpXmlEntitiesClient(); +await client.GetTimeZoneAsync(); +``` + +## Exception Handling + +When the API returns a non-success status code (4xx or 5xx response), a subclass of the following error +will be thrown. + +```csharp +using SeedCsharpXmlEntities; + +try { + var response = await client.GetTimeZoneAsync(...); +} catch (SeedCsharpXmlEntitiesApiException e) { + System.Console.WriteLine(e.Body); + System.Console.WriteLine(e.StatusCode); + + // Access the raw HTTP response (status code, URL, headers) off the exception + var rawResponse = e.RawResponse; + if (rawResponse != null) + { + System.Console.WriteLine(rawResponse.Url); + if (rawResponse.Headers.TryGetValue("X-Request-Id", out var requestId)) + { + System.Console.WriteLine($"Request ID: {requestId}"); + } + } +} +``` + +## Advanced + +### Retries + +The SDK is instrumented with automatic retries with exponential backoff. A request will be retried as long +as the request is deemed retryable and the number of retry attempts has not grown larger than the configured +retry limit (default: 2). + +Which status codes are retried depends on the `retryStatusCodes` generator configuration: + +**`legacy`** (current default): retries on +- [408](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) (Timeout) +- [429](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) (Too Many Requests) +- [5XX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#server_error_responses) (All server errors, including 500) + +**`recommended`**: retries on +- [408](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) (Timeout) +- [429](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) (Too Many Requests) +- [502](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502) (Bad Gateway) +- [503](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503) (Service Unavailable) +- [504](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504) (Gateway Timeout) + +Use the `MaxRetries` request option to configure this behavior. + +```csharp +var response = await client.GetTimeZoneAsync( + ..., + new RequestOptions { + MaxRetries = 0 // Override MaxRetries at the request level + } +); +``` + +### Timeouts + +The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure this behavior. + +```csharp +var response = await client.GetTimeZoneAsync( + ..., + new RequestOptions { + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s + } +); +``` + +### Raw Response + +Access raw HTTP response data (status code, headers, URL) alongside parsed response data using the `.WithRawResponse()` method. + +```csharp +using SeedCsharpXmlEntities; + +// Access raw response data (status code, headers, etc.) alongside the parsed response +var result = await client.GetTimeZoneAsync(...).WithRawResponse(); + +// Access the parsed data +var data = result.Data; + +// Access raw response metadata +var statusCode = result.RawResponse.StatusCode; +var headers = result.RawResponse.Headers; +var url = result.RawResponse.Url; + +// Access specific headers (case-insensitive) +if (headers.TryGetValue("X-Request-Id", out var requestId)) +{ + System.Console.WriteLine($"Request ID: {requestId}"); +} + +// For the default behavior, simply await without .WithRawResponse() +var parsedData = await client.GetTimeZoneAsync(...); + +// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) +// and on endpoints with no response body (returns RawResponse only). +``` + +### Additional Headers + +If you would like to send additional headers as part of the request, use the `AdditionalHeaders` request option. + +```csharp +var response = await client.GetTimeZoneAsync( + ..., + new RequestOptions { + AdditionalHeaders = new Dictionary + { + { "X-Custom-Header", "custom-value" } + } + } +); +``` + +### Additional Query Parameters + +If you would like to send additional query parameters as part of the request, use the `AdditionalQueryParameters` request option. + +```csharp +var response = await client.GetTimeZoneAsync( + ..., + new RequestOptions { + AdditionalQueryParameters = new Dictionary + { + { "custom_param", "custom-value" } + } + } +); +``` + +### Additional Body Properties + +If you would like to send additional body properties as part of the request, use the `AdditionalBodyProperties` request option. +This is only applied to JSON requests. + +```csharp +var response = await client.GetTimeZoneAsync( + ..., + new RequestOptions { + AdditionalBodyProperties = new Dictionary + { + { "custom_field", "custom-value" } + } + } +); +``` + +## Contributing + +While we value open-source contributions to this SDK, this library is generated programmatically. +Additions made directly to this library would have to be moved over to our generation code, +otherwise they would be overwritten upon the next generated release. Feel free to open a PR as +a proof of concept, but know that we will not be able to merge it as-is. We suggest opening +an issue first to discuss with us! + +On the other hand, contributions to the README are always very welcome! diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/SeedCsharpXmlEntities.slnx b/seed/csharp-sdk/csharp-xml-entities/package-metadata/SeedCsharpXmlEntities.slnx new file mode 100644 index 000000000000..706a3f8d4cb4 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/SeedCsharpXmlEntities.slnx @@ -0,0 +1,4 @@ + + + + diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/Snippets/Example0.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/Snippets/Example0.cs new file mode 100644 index 000000000000..1db08fcd34b7 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/Snippets/Example0.cs @@ -0,0 +1,15 @@ +using SeedCsharpXmlEntities; + +public partial class Examples +{ + public async Task Example0() { + var client = new SeedCsharpXmlEntitiesClient( + clientOptions: new ClientOptions { + BaseUrl = "https://api.fern.com" + } + ); + + await client.GetTimeZoneAsync(); + } + +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/Snippets/Snippets.csproj b/seed/csharp-sdk/csharp-xml-entities/package-metadata/Snippets/Snippets.csproj new file mode 100644 index 000000000000..8d1c06d60829 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/Snippets/Snippets.csproj @@ -0,0 +1,11 @@ + + + net10.0 + Snippets + enable + enable + + + + + \ No newline at end of file diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/reference.md b/seed/csharp-sdk/csharp-xml-entities/package-metadata/reference.md new file mode 100644 index 000000000000..3a397642ffbc --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/reference.md @@ -0,0 +1,40 @@ +# Reference +
client.GetTimeZoneAsync() -> WithRawResponseTask<TimeZoneModel> +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get timezone information with + offset +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.GetTimeZoneAsync(); +``` +
+
+
+
+ + +
+
+
+ diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/snippet.json b/seed/csharp-sdk/csharp-xml-entities/package-metadata/snippet.json new file mode 100644 index 000000000000..0c0af050ab0f --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/snippet.json @@ -0,0 +1,17 @@ +{ + "types": {}, + "endpoints": [ + { + "example_identifier": null, + "id": { + "path": "/timezone", + "method": "GET", + "identifier_override": "endpoint_.getTimeZone" + }, + "snippet": { + "type": "csharp", + "client": "using SeedCsharpXmlEntities;\n\nvar client = new SeedCsharpXmlEntitiesClient();\nawait client.GetTimeZoneAsync();\n" + } + } + ] +} \ No newline at end of file diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/HeadersBuilderTests.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/HeadersBuilderTests.cs new file mode 100644 index 000000000000..d946b28d4ded --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/HeadersBuilderTests.cs @@ -0,0 +1,326 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core; + +[TestFixture] +public class HeadersBuilderTests +{ + [Test] + public async global::System.Threading.Tasks.Task Add_SimpleHeaders() + { + var headers = await new HeadersBuilder.Builder() + .Add("Content-Type", "application/json") + .Add("Authorization", "Bearer token123") + .Add("X-API-Key", "key456") + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(3)); + Assert.That(headers["Content-Type"], Is.EqualTo("application/json")); + Assert.That(headers["Authorization"], Is.EqualTo("Bearer token123")); + Assert.That(headers["X-API-Key"], Is.EqualTo("key456")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_NullValuesIgnored() + { + var headers = await new HeadersBuilder.Builder() + .Add("Header1", "value1") + .Add("Header2", null) + .Add("Header3", "value3") + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(2)); + Assert.That(headers.ContainsKey("Header1"), Is.True); + Assert.That(headers.ContainsKey("Header2"), Is.False); + Assert.That(headers.ContainsKey("Header3"), Is.True); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_OverwritesExistingHeader() + { + var headers = await new HeadersBuilder.Builder() + .Add("Content-Type", "application/json") + .Add("Content-Type", "application/xml") + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(1)); + Assert.That(headers["Content-Type"], Is.EqualTo("application/xml")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_HeadersOverload_MergesExistingHeaders() + { + var existingHeaders = new Headers( + new Dictionary { { "Header1", "value1" }, { "Header2", "value2" } } + ); + + var result = await new HeadersBuilder.Builder() + .Add("Header3", "value3") + .Add(existingHeaders) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(result.Count, Is.EqualTo(3)); + Assert.That(result["Header1"], Is.EqualTo("value1")); + Assert.That(result["Header2"], Is.EqualTo("value2")); + Assert.That(result["Header3"], Is.EqualTo("value3")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_HeadersOverload_OverwritesExistingHeaders() + { + var existingHeaders = new Headers( + new Dictionary { { "Header1", "override" } } + ); + + var result = await new HeadersBuilder.Builder() + .Add("Header1", "original") + .Add("Header2", "keep") + .Add(existingHeaders) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(result.Count, Is.EqualTo(2)); + Assert.That(result["Header1"], Is.EqualTo("override")); + Assert.That(result["Header2"], Is.EqualTo("keep")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_HeadersOverload_NullHeadersIgnored() + { + var result = await new HeadersBuilder.Builder() + .Add("Header1", "value1") + .Add((Headers?)null) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(result.Count, Is.EqualTo(1)); + Assert.That(result["Header1"], Is.EqualTo("value1")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_KeyValuePairOverload_AddsHeaders() + { + var additionalHeaders = new List> + { + new("Header1", "value1"), + new("Header2", "value2"), + }; + + var headers = await new HeadersBuilder.Builder() + .Add("Header3", "value3") + .Add(additionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(3)); + Assert.That(headers["Header1"], Is.EqualTo("value1")); + Assert.That(headers["Header2"], Is.EqualTo("value2")); + Assert.That(headers["Header3"], Is.EqualTo("value3")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_KeyValuePairOverload_IgnoresNullValues() + { + var additionalHeaders = new List> + { + new("Header1", "value1"), + new("Header2", null), // Should be ignored + }; + + var headers = await new HeadersBuilder.Builder() + .Add(additionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(1)); + Assert.That(headers.ContainsKey("Header2"), Is.False); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_DictionaryOverload_AddsHeaders() + { + var dict = new Dictionary + { + { "Header1", "value1" }, + { "Header2", "value2" }, + }; + + var headers = await new HeadersBuilder.Builder() + .Add("Header3", "value3") + .Add(dict) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(3)); + Assert.That(headers["Header1"], Is.EqualTo("value1")); + Assert.That(headers["Header2"], Is.EqualTo("value2")); + Assert.That(headers["Header3"], Is.EqualTo("value3")); + } + + [Test] + public async global::System.Threading.Tasks.Task EmptyBuilder_ReturnsEmptyHeaders() + { + var headers = await new HeadersBuilder.Builder().BuildAsync().ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(0)); + } + + [Test] + public async global::System.Threading.Tasks.Task OnlyNullValues_ReturnsEmptyHeaders() + { + var headers = await new HeadersBuilder.Builder() + .Add("Header1", null) + .Add("Header2", null) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(0)); + } + + [Test] + public async global::System.Threading.Tasks.Task ComplexMergingScenario() + { + // Simulates real SDK usage: endpoint headers + client headers + request options + var clientHeaders = new Headers( + new Dictionary + { + { "X-Client-Version", "1.0.0" }, + { "User-Agent", "MyClient/1.0" }, + } + ); + + var clientAdditionalHeaders = new List> + { + new("X-Custom-Header", "custom-value"), + }; + + var requestOptionsHeaders = new Headers( + new Dictionary + { + { "Authorization", "Bearer user-token" }, + { "User-Agent", "MyClient/2.0" }, // Override + } + ); + + var requestAdditionalHeaders = new List> + { + new("X-Request-ID", "req-123"), + new("X-Custom-Header", "overridden-value"), // Override + }; + + var headers = await new HeadersBuilder.Builder() + .Add("Content-Type", "application/json") // Endpoint header + .Add("X-Endpoint-ID", "endpoint-1") + .Add(clientHeaders) + .Add(clientAdditionalHeaders) + .Add(requestOptionsHeaders) + .Add(requestAdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + + // Verify precedence + Assert.That(headers["Content-Type"], Is.EqualTo("application/json")); + Assert.That(headers["X-Endpoint-ID"], Is.EqualTo("endpoint-1")); + Assert.That(headers["X-Client-Version"], Is.EqualTo("1.0.0")); + Assert.That(headers["User-Agent"], Is.EqualTo("MyClient/2.0")); // Overridden + Assert.That(headers["Authorization"], Is.EqualTo("Bearer user-token")); + Assert.That(headers["X-Request-ID"], Is.EqualTo("req-123")); + Assert.That(headers["X-Custom-Header"], Is.EqualTo("overridden-value")); // Overridden + } + + [Test] + public async global::System.Threading.Tasks.Task Builder_WithCapacity() + { + // Test that capacity constructor works without errors + var headers = await new HeadersBuilder.Builder(capacity: 10) + .Add("Header1", "value1") + .Add("Header2", "value2") + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(2)); + Assert.That(headers["Header1"], Is.EqualTo("value1")); + Assert.That(headers["Header2"], Is.EqualTo("value2")); + } + + [Test] + public async global::System.Threading.Tasks.Task Add_HeadersOverload_ResolvesDynamicHeaderValues() + { + // Test that BuildAsync properly resolves HeaderValue instances + var existingHeaders = new Headers(); + existingHeaders["DynamicHeader"] = + (Func>)( + () => global::System.Threading.Tasks.Task.FromResult("dynamic-value") + ); + + var result = await new HeadersBuilder.Builder() + .Add("StaticHeader", "static-value") + .Add(existingHeaders) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(result.Count, Is.EqualTo(2)); + Assert.That(result["StaticHeader"], Is.EqualTo("static-value")); + Assert.That(result["DynamicHeader"], Is.EqualTo("dynamic-value")); + } + + [Test] + public async global::System.Threading.Tasks.Task MultipleSyncAdds() + { + var headers1 = new Headers(new Dictionary { { "H1", "v1" } }); + var headers2 = new Headers(new Dictionary { { "H2", "v2" } }); + var headers3 = new Headers(new Dictionary { { "H3", "v3" } }); + + var result = await new HeadersBuilder.Builder() + .Add(headers1) + .Add(headers2) + .Add(headers3) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(result.Count, Is.EqualTo(3)); + Assert.That(result["H1"], Is.EqualTo("v1")); + Assert.That(result["H2"], Is.EqualTo("v2")); + Assert.That(result["H3"], Is.EqualTo("v3")); + } + + [Test] + public async global::System.Threading.Tasks.Task PrecedenceOrder_LatestWins() + { + // Test that later operations override earlier ones + var headers1 = new Headers(new Dictionary { { "Key", "value1" } }); + var headers2 = new Headers(new Dictionary { { "Key", "value2" } }); + var additional = new List> { new("Key", "value3") }; + + var result = await new HeadersBuilder.Builder() + .Add("Key", "value0") + .Add(headers1) + .Add(headers2) + .Add(additional) + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(result["Key"], Is.EqualTo("value3")); + } + + [Test] + public async global::System.Threading.Tasks.Task CaseInsensitiveKeys() + { + // Test that header keys are case-insensitive + var headers = await new HeadersBuilder.Builder() + .Add("content-type", "application/json") + .Add("Content-Type", "application/xml") // Should overwrite + .BuildAsync() + .ConfigureAwait(false); + + Assert.That(headers.Count, Is.EqualTo(1)); + Assert.That(headers["content-type"], Is.EqualTo("application/xml")); + Assert.That(headers["Content-Type"], Is.EqualTo("application/xml")); + Assert.That(headers["CONTENT-TYPE"], Is.EqualTo("application/xml")); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/AdditionalPropertiesTests.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/AdditionalPropertiesTests.cs new file mode 100644 index 000000000000..2cfb0e4a4b18 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/AdditionalPropertiesTests.cs @@ -0,0 +1,365 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core.Json; + +[TestFixture] +public class AdditionalPropertiesTests +{ + [Test] + public void Record_OnDeserialized_ShouldPopulateAdditionalProperties() + { + // Arrange + const string json = """ + { + "id": "1", + "category": "fiction", + "title": "The Hobbit" + } + """; + + // Act + var record = JsonUtils.Deserialize(json); + + // Assert + Assert.That(record, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(record.Id, Is.EqualTo("1")); + Assert.That(record.AdditionalProperties["category"].GetString(), Is.EqualTo("fiction")); + Assert.That(record.AdditionalProperties["title"].GetString(), Is.EqualTo("The Hobbit")); + }); + } + + [Test] + public void RecordWithWriteableAdditionalProperties_OnSerialization_ShouldIncludeAdditionalProperties() + { + // Arrange + var record = new WriteableRecord + { + Id = "1", + AdditionalProperties = { ["category"] = "fiction", ["title"] = "The Hobbit" }, + }; + + // Act + var json = JsonUtils.Serialize(record); + var deserializedRecord = JsonUtils.Deserialize(json); + + // Assert + Assert.That(deserializedRecord, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(deserializedRecord.Id, Is.EqualTo("1")); + Assert.That( + deserializedRecord.AdditionalProperties["category"], + Is.InstanceOf() + ); + Assert.That( + ((JsonElement)deserializedRecord.AdditionalProperties["category"]!).GetString(), + Is.EqualTo("fiction") + ); + Assert.That( + deserializedRecord.AdditionalProperties["title"], + Is.InstanceOf() + ); + Assert.That( + ((JsonElement)deserializedRecord.AdditionalProperties["title"]!).GetString(), + Is.EqualTo("The Hobbit") + ); + }); + } + + [Test] + public void ReadOnlyAdditionalProperties_ShouldRetrieveValuesCorrectly() + { + // Arrange + var extensionData = new Dictionary + { + ["key1"] = JsonUtils.SerializeToElement("value1"), + ["key2"] = JsonUtils.SerializeToElement(123), + }; + var readOnlyProps = new ReadOnlyAdditionalProperties(); + readOnlyProps.CopyFromExtensionData(extensionData); + + // Act & Assert + Assert.That(readOnlyProps["key1"].GetString(), Is.EqualTo("value1")); + Assert.That(readOnlyProps["key2"].GetInt32(), Is.EqualTo(123)); + } + + [Test] + public void AdditionalProperties_ShouldBehaveAsDictionary() + { + // Arrange + var additionalProps = new AdditionalProperties { ["key1"] = "value1", ["key2"] = 123 }; + + // Act + additionalProps["key3"] = true; + + // Assert + Assert.Multiple(() => + { + Assert.That(additionalProps["key1"], Is.EqualTo("value1")); + Assert.That(additionalProps["key2"], Is.EqualTo(123)); + Assert.That((bool)additionalProps["key3"]!, Is.True); + Assert.That(additionalProps.Count, Is.EqualTo(3)); + }); + } + + [Test] + public void AdditionalProperties_ToJsonObject_ShouldSerializeCorrectly() + { + // Arrange + var additionalProps = new AdditionalProperties { ["key1"] = "value1", ["key2"] = 123 }; + + // Act + var jsonObject = additionalProps.ToJsonObject(); + + Assert.Multiple(() => + { + // Assert + Assert.That(jsonObject["key1"]!.GetValue(), Is.EqualTo("value1")); + Assert.That(jsonObject["key2"]!.GetValue(), Is.EqualTo(123)); + }); + } + + [Test] + public void AdditionalProperties_MixReadAndWrite_ShouldOverwriteDeserializedProperty() + { + // Arrange + const string json = """ + { + "id": "1", + "category": "fiction", + "title": "The Hobbit" + } + """; + var record = JsonUtils.Deserialize(json); + + // Act + record.AdditionalProperties["category"] = "non-fiction"; + + // Assert + Assert.Multiple(() => + { + Assert.That(record, Is.Not.Null); + Assert.That(record.Id, Is.EqualTo("1")); + Assert.That(record.AdditionalProperties["category"], Is.EqualTo("non-fiction")); + Assert.That(record.AdditionalProperties["title"], Is.InstanceOf()); + Assert.That( + ((JsonElement)record.AdditionalProperties["title"]!).GetString(), + Is.EqualTo("The Hobbit") + ); + }); + } + + [Test] + public void RecordWithReadonlyAdditionalPropertiesInts_OnDeserialized_ShouldPopulateAdditionalProperties() + { + // Arrange + const string json = """ + { + "extra1": 42, + "extra2": 99 + } + """; + + // Act + var record = JsonUtils.Deserialize(json); + + // Assert + Assert.That(record, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(record.AdditionalProperties["extra1"], Is.EqualTo(42)); + Assert.That(record.AdditionalProperties["extra2"], Is.EqualTo(99)); + }); + } + + [Test] + public void RecordWithAdditionalPropertiesInts_OnSerialization_ShouldIncludeAdditionalProperties() + { + // Arrange + var record = new WriteableRecordWithInts + { + AdditionalProperties = { ["extra1"] = 42, ["extra2"] = 99 }, + }; + + // Act + var json = JsonUtils.Serialize(record); + var deserializedRecord = JsonUtils.Deserialize(json); + + // Assert + Assert.That(deserializedRecord, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(deserializedRecord.AdditionalProperties["extra1"], Is.EqualTo(42)); + Assert.That(deserializedRecord.AdditionalProperties["extra2"], Is.EqualTo(99)); + }); + } + + [Test] + public void RecordWithReadonlyAdditionalPropertiesDictionaries_OnDeserialized_ShouldPopulateAdditionalProperties() + { + // Arrange + const string json = """ + { + "extra1": { "key1": true, "key2": false }, + "extra2": { "key3": true } + } + """; + + // Act + var record = JsonUtils.Deserialize(json); + + // Assert + Assert.That(record, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(record.AdditionalProperties["extra1"]["key1"], Is.True); + Assert.That(record.AdditionalProperties["extra1"]["key2"], Is.False); + Assert.That(record.AdditionalProperties["extra2"]["key3"], Is.True); + }); + } + + [Test] + public void RecordWithAdditionalPropertiesDictionaries_OnSerialization_ShouldIncludeAdditionalProperties() + { + // Arrange + var record = new WriteableRecordWithDictionaries + { + AdditionalProperties = + { + ["extra1"] = new Dictionary { { "key1", true }, { "key2", false } }, + ["extra2"] = new Dictionary { { "key3", true } }, + }, + }; + + // Act + var json = JsonUtils.Serialize(record); + var deserializedRecord = JsonUtils.Deserialize(json); + + // Assert + Assert.That(deserializedRecord, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(deserializedRecord.AdditionalProperties["extra1"]["key1"], Is.True); + Assert.That(deserializedRecord.AdditionalProperties["extra1"]["key2"], Is.False); + Assert.That(deserializedRecord.AdditionalProperties["extra2"]["key3"], Is.True); + }); + } + + private record Record : IJsonOnDeserialized + { + [JsonPropertyName("id")] + public required string Id { get; set; } + + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; } = new(); + + void IJsonOnDeserialized.OnDeserialized() + { + AdditionalProperties.CopyFromExtensionData(_extensionData); + } + } + + private record WriteableRecord : IJsonOnDeserialized, IJsonOnSerializing + { + [JsonPropertyName("id")] + public required string Id { get; set; } + + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonIgnore] + public AdditionalProperties AdditionalProperties { get; set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() + { + AdditionalProperties.CopyFromExtensionData(_extensionData); + } + + void IJsonOnSerializing.OnSerializing() + { + AdditionalProperties.CopyToExtensionData(_extensionData); + } + } + + private record RecordWithInts : IJsonOnDeserialized + { + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; } = new(); + + void IJsonOnDeserialized.OnDeserialized() + { + AdditionalProperties.CopyFromExtensionData(_extensionData); + } + } + + private record WriteableRecordWithInts : IJsonOnDeserialized, IJsonOnSerializing + { + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonIgnore] + public AdditionalProperties AdditionalProperties { get; } = new(); + + void IJsonOnDeserialized.OnDeserialized() + { + AdditionalProperties.CopyFromExtensionData(_extensionData); + } + + void IJsonOnSerializing.OnSerializing() + { + AdditionalProperties.CopyToExtensionData(_extensionData); + } + } + + private record RecordWithDictionaries : IJsonOnDeserialized + { + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonIgnore] + public ReadOnlyAdditionalProperties< + Dictionary + > AdditionalProperties { get; } = new(); + + void IJsonOnDeserialized.OnDeserialized() + { + AdditionalProperties.CopyFromExtensionData(_extensionData); + } + } + + private record WriteableRecordWithDictionaries : IJsonOnDeserialized, IJsonOnSerializing + { + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonIgnore] + public AdditionalProperties> AdditionalProperties { get; } = new(); + + void IJsonOnDeserialized.OnDeserialized() + { + AdditionalProperties.CopyFromExtensionData(_extensionData); + } + + void IJsonOnSerializing.OnSerializing() + { + AdditionalProperties.CopyToExtensionData(_extensionData); + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/DateOnlyJsonTests.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/DateOnlyJsonTests.cs new file mode 100644 index 000000000000..af1ea78d56b9 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/DateOnlyJsonTests.cs @@ -0,0 +1,100 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core.Json; + +[TestFixture] +public class DateOnlyJsonTests +{ + [Test] + public void SerializeDateOnly_ShouldMatchExpectedFormat() + { + (DateOnly dateOnly, string expected)[] testCases = + [ + (new DateOnly(2023, 10, 5), "\"2023-10-05\""), + (new DateOnly(2023, 1, 1), "\"2023-01-01\""), + (new DateOnly(2023, 12, 31), "\"2023-12-31\""), + (new DateOnly(2023, 6, 15), "\"2023-06-15\""), + (new DateOnly(2023, 3, 10), "\"2023-03-10\""), + ]; + foreach (var (dateOnly, expected) in testCases) + { + var json = JsonUtils.Serialize(dateOnly); + Assert.That(json, Is.EqualTo(expected)); + } + } + + [Test] + public void DeserializeDateOnly_ShouldMatchExpectedDateOnly() + { + (DateOnly expected, string json)[] testCases = + [ + (new DateOnly(2023, 10, 5), "\"2023-10-05\""), + (new DateOnly(2023, 1, 1), "\"2023-01-01\""), + (new DateOnly(2023, 12, 31), "\"2023-12-31\""), + (new DateOnly(2023, 6, 15), "\"2023-06-15\""), + (new DateOnly(2023, 3, 10), "\"2023-03-10\""), + ]; + + foreach (var (expected, json) in testCases) + { + var dateOnly = JsonUtils.Deserialize(json); + Assert.That(dateOnly, Is.EqualTo(expected)); + } + } + + [Test] + public void SerializeNullableDateOnly_ShouldMatchExpectedFormat() + { + (DateOnly? dateOnly, string expected)[] testCases = + [ + (new DateOnly(2023, 10, 5), "\"2023-10-05\""), + (null, "null"), + ]; + foreach (var (dateOnly, expected) in testCases) + { + var json = JsonUtils.Serialize(dateOnly); + Assert.That(json, Is.EqualTo(expected)); + } + } + + [Test] + public void DeserializeNullableDateOnly_ShouldMatchExpectedDateOnly() + { + (DateOnly? expected, string json)[] testCases = + [ + (new DateOnly(2023, 10, 5), "\"2023-10-05\""), + (null, "null"), + ]; + + foreach (var (expected, json) in testCases) + { + var dateOnly = JsonUtils.Deserialize(json); + Assert.That(dateOnly, Is.EqualTo(expected)); + } + } + + [Test] + public void ShouldSerializeDictionaryWithDateOnlyKey() + { + var key = new DateOnly(2023, 10, 5); + var dict = new Dictionary { { key, "value_a" } }; + var json = JsonUtils.Serialize(dict); + Assert.That(json, Does.Contain("2023-10-05")); + Assert.That(json, Does.Contain("value_a")); + } + + [Test] + public void ShouldDeserializeDictionaryWithDateOnlyKey() + { + var json = """ + { + "2023-10-05": "value_a" + } + """; + var dict = JsonUtils.Deserialize>(json); + Assert.That(dict, Is.Not.Null); + var key = new DateOnly(2023, 10, 5); + Assert.That(dict![key], Is.EqualTo("value_a")); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/DateTimeJsonTests.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/DateTimeJsonTests.cs new file mode 100644 index 000000000000..5d878a684a26 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/DateTimeJsonTests.cs @@ -0,0 +1,134 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core.Json; + +[TestFixture] +public class DateTimeJsonTests +{ + [Test] + public void SerializeDateTime_ShouldMatchExpectedFormat() + { + (DateTime dateTime, string expected)[] testCases = + [ + ( + new DateTime(2023, 10, 5, 14, 30, 0, DateTimeKind.Utc), + "\"2023-10-05T14:30:00.000Z\"" + ), + (new DateTime(2023, 1, 1, 0, 0, 0, DateTimeKind.Utc), "\"2023-01-01T00:00:00.000Z\""), + ( + new DateTime(2023, 12, 31, 23, 59, 59, DateTimeKind.Utc), + "\"2023-12-31T23:59:59.000Z\"" + ), + (new DateTime(2023, 6, 15, 12, 0, 0, DateTimeKind.Utc), "\"2023-06-15T12:00:00.000Z\""), + ( + new DateTime(2023, 3, 10, 8, 45, 30, DateTimeKind.Utc), + "\"2023-03-10T08:45:30.000Z\"" + ), + ( + new DateTime(2023, 3, 10, 8, 45, 30, 123, DateTimeKind.Utc), + "\"2023-03-10T08:45:30.123Z\"" + ), + ]; + foreach (var (dateTime, expected) in testCases) + { + var json = JsonUtils.Serialize(dateTime); + Assert.That(json, Is.EqualTo(expected)); + } + } + + [Test] + public void DeserializeDateTime_ShouldMatchExpectedDateTime() + { + (DateTime expected, string json)[] testCases = + [ + ( + new DateTime(2023, 10, 5, 14, 30, 0, DateTimeKind.Utc), + "\"2023-10-05T14:30:00.000Z\"" + ), + (new DateTime(2023, 1, 1, 0, 0, 0, DateTimeKind.Utc), "\"2023-01-01T00:00:00.000Z\""), + ( + new DateTime(2023, 12, 31, 23, 59, 59, DateTimeKind.Utc), + "\"2023-12-31T23:59:59.000Z\"" + ), + (new DateTime(2023, 6, 15, 12, 0, 0, DateTimeKind.Utc), "\"2023-06-15T12:00:00.000Z\""), + ( + new DateTime(2023, 3, 10, 8, 45, 30, DateTimeKind.Utc), + "\"2023-03-10T08:45:30.000Z\"" + ), + (new DateTime(2023, 3, 10, 8, 45, 30, DateTimeKind.Utc), "\"2023-03-10T08:45:30Z\""), + ( + new DateTime(2023, 3, 10, 8, 45, 30, 123, DateTimeKind.Utc), + "\"2023-03-10T08:45:30.123Z\"" + ), + ]; + + foreach (var (expected, json) in testCases) + { + var dateTime = JsonUtils.Deserialize(json); + Assert.That(dateTime, Is.EqualTo(expected)); + } + } + + [Test] + public void SerializeNullableDateTime_ShouldMatchExpectedFormat() + { + (DateTime? expected, string json)[] testCases = + [ + ( + new DateTime(2023, 10, 5, 14, 30, 0, DateTimeKind.Utc), + "\"2023-10-05T14:30:00.000Z\"" + ), + (null, "null"), + ]; + + foreach (var (expected, json) in testCases) + { + var dateTime = JsonUtils.Deserialize(json); + Assert.That(dateTime, Is.EqualTo(expected)); + } + } + + [Test] + public void DeserializeNullableDateTime_ShouldMatchExpectedDateTime() + { + (DateTime? expected, string json)[] testCases = + [ + ( + new DateTime(2023, 10, 5, 14, 30, 0, DateTimeKind.Utc), + "\"2023-10-05T14:30:00.000Z\"" + ), + (null, "null"), + ]; + + foreach (var (expected, json) in testCases) + { + var dateTime = JsonUtils.Deserialize(json); + Assert.That(dateTime, Is.EqualTo(expected)); + } + } + + [Test] + public void ShouldSerializeDictionaryWithDateTimeKey() + { + var key = new DateTime(2023, 10, 5, 14, 30, 0, DateTimeKind.Utc); + var dict = new Dictionary { { key, "value_a" } }; + var json = JsonUtils.Serialize(dict); + Assert.That(json, Does.Contain("2023-10-05T14:30:00.000Z")); + Assert.That(json, Does.Contain("value_a")); + } + + [Test] + public void ShouldDeserializeDictionaryWithDateTimeKey() + { + var json = """ + { + "2023-10-05T14:30:00.000Z": "value_a" + } + """; + var dict = JsonUtils.Deserialize>(json); + Assert.That(dict, Is.Not.Null); + var key = new DateTime(2023, 10, 5, 14, 30, 0, DateTimeKind.Utc); + Assert.That(dict![key], Is.EqualTo("value_a")); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/JsonAccessAttributeTests.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/JsonAccessAttributeTests.cs new file mode 100644 index 000000000000..8ec2b9b8ae13 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/Json/JsonAccessAttributeTests.cs @@ -0,0 +1,160 @@ +using global::System.Text.Json.Serialization; +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core.Json; + +[TestFixture] +public class JsonAccessAttributeTests +{ + private class MyClass + { + [JsonPropertyName("read_only_prop")] + [JsonAccess(JsonAccessType.ReadOnly)] + public string? ReadOnlyProp { get; set; } + + [JsonPropertyName("write_only_prop")] + [JsonAccess(JsonAccessType.WriteOnly)] + public string? WriteOnlyProp { get; set; } + + [JsonPropertyName("normal_prop")] + public string? NormalProp { get; set; } + + [JsonPropertyName("read_only_nullable_list")] + [JsonAccess(JsonAccessType.ReadOnly)] + public IEnumerable? ReadOnlyNullableList { get; set; } + + [JsonPropertyName("read_only_list")] + [JsonAccess(JsonAccessType.ReadOnly)] + public IEnumerable ReadOnlyList { get; set; } = []; + + [JsonPropertyName("write_only_nullable_list")] + [JsonAccess(JsonAccessType.WriteOnly)] + public IEnumerable? WriteOnlyNullableList { get; set; } + + [JsonPropertyName("write_only_list")] + [JsonAccess(JsonAccessType.WriteOnly)] + public IEnumerable WriteOnlyList { get; set; } = []; + + [JsonPropertyName("normal_list")] + public IEnumerable NormalList { get; set; } = []; + + [JsonPropertyName("normal_nullable_list")] + public IEnumerable? NullableNormalList { get; set; } + } + + [Test] + public void JsonAccessAttribute_ShouldWorkAsExpected() + { + const string json = """ + { + "read_only_prop": "read", + "write_only_prop": "write", + "normal_prop": "normal_prop", + "read_only_nullable_list": ["item1", "item2"], + "read_only_list": ["item3", "item4"], + "write_only_nullable_list": ["item5", "item6"], + "write_only_list": ["item7", "item8"], + "normal_list": ["normal1", "normal2"], + "normal_nullable_list": ["normal1", "normal2"] + } + """; + var obj = JsonUtils.Deserialize(json); + + Assert.Multiple(() => + { + // String properties + Assert.That(obj.ReadOnlyProp, Is.EqualTo("read")); + Assert.That(obj.WriteOnlyProp, Is.Null); + Assert.That(obj.NormalProp, Is.EqualTo("normal_prop")); + + // List properties - read only + var nullableReadOnlyList = obj.ReadOnlyNullableList?.ToArray(); + Assert.That(nullableReadOnlyList, Is.Not.Null); + Assert.That(nullableReadOnlyList, Has.Length.EqualTo(2)); + Assert.That(nullableReadOnlyList![0], Is.EqualTo("item1")); + Assert.That(nullableReadOnlyList![1], Is.EqualTo("item2")); + + var readOnlyList = obj.ReadOnlyList.ToArray(); + Assert.That(readOnlyList, Is.Not.Null); + Assert.That(readOnlyList, Has.Length.EqualTo(2)); + Assert.That(readOnlyList[0], Is.EqualTo("item3")); + Assert.That(readOnlyList[1], Is.EqualTo("item4")); + + // List properties - write only + Assert.That(obj.WriteOnlyNullableList, Is.Null); + Assert.That(obj.WriteOnlyList, Is.Not.Null); + Assert.That(obj.WriteOnlyList, Is.Empty); + + // Normal list property + var normalList = obj.NormalList.ToArray(); + Assert.That(normalList, Is.Not.Null); + Assert.That(normalList, Has.Length.EqualTo(2)); + Assert.That(normalList[0], Is.EqualTo("normal1")); + Assert.That(normalList[1], Is.EqualTo("normal2")); + }); + + // Set up values for serialization + obj.WriteOnlyProp = "write"; + obj.NormalProp = "new_value"; + obj.WriteOnlyNullableList = new List { "write1", "write2" }; + obj.WriteOnlyList = new List { "write3", "write4" }; + obj.NormalList = new List { "new_normal" }; + obj.NullableNormalList = new List { "new_normal" }; + + var serializedJson = JsonUtils.Serialize(obj); + const string expectedJson = """ + { + "write_only_prop": "write", + "normal_prop": "new_value", + "write_only_nullable_list": [ + "write1", + "write2" + ], + "write_only_list": [ + "write3", + "write4" + ], + "normal_list": [ + "new_normal" + ], + "normal_nullable_list": [ + "new_normal" + ] + } + """; + Assert.That(serializedJson, Is.EqualTo(expectedJson).IgnoreWhiteSpace); + } + + [Test] + public void JsonAccessAttribute_WithNullListsInJson_ShouldWorkAsExpected() + { + const string json = """ + { + "read_only_prop": "read", + "normal_prop": "normal_prop", + "read_only_nullable_list": null, + "read_only_list": [] + } + """; + var obj = JsonUtils.Deserialize(json); + + Assert.Multiple(() => + { + // Read-only nullable list should be null when JSON contains null + var nullableReadOnlyList = obj.ReadOnlyNullableList?.ToArray(); + Assert.That(nullableReadOnlyList, Is.Null); + + // Read-only non-nullable list should never be null, but empty when JSON contains null + var readOnlyList = obj.ReadOnlyList.ToArray(); // This should be initialized to an empty list by default + Assert.That(readOnlyList, Is.Not.Null); + Assert.That(readOnlyList, Is.Empty); + }); + + // Serialize and verify read-only lists are not included + var serializedJson = JsonUtils.Serialize(obj); + Assert.That(serializedJson, Does.Not.Contain("read_only_prop")); + Assert.That(serializedJson, Does.Not.Contain("read_only_nullable_list")); + Assert.That(serializedJson, Does.Not.Contain("read_only_list")); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/QueryStringBuilderTests.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/QueryStringBuilderTests.cs new file mode 100644 index 000000000000..ce6e70558eea --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/QueryStringBuilderTests.cs @@ -0,0 +1,672 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core; + +[TestFixture] +public class QueryStringBuilderTests +{ + [Test] + public void Build_SimpleParameters() + { + var parameters = new List> + { + new("name", "John Doe"), + new("age", "30"), + new("city", "New York"), + }; + + var result = QueryStringBuilder.Build(parameters); + + Assert.That(result, Is.EqualTo("?name=John%20Doe&age=30&city=New%20York")); + } + + [Test] + public void Build_EmptyList_ReturnsEmptyString() + { + var parameters = new List>(); + + var result = QueryStringBuilder.Build(parameters); + + Assert.That(result, Is.EqualTo(string.Empty)); + } + + [Test] + public void Build_SpecialCharacters() + { + var parameters = new List> + { + new("email", "test@example.com"), + new("url", "https://example.com/path?query=value"), + new("special", "a+b=c&d"), + }; + + var result = QueryStringBuilder.Build(parameters); + + Assert.That( + result, + Is.EqualTo( + "?email=test@example.com&url=https://example.com/path?query=value&special=a%2Bb=c%26d" + ) + ); + } + + [Test] + public void Build_UnicodeCharacters() + { + var parameters = new List> { new("greeting", "Hello 世界") }; + + var result = QueryStringBuilder.Build(parameters); + + // Verify the Chinese characters are properly UTF-8 encoded + Assert.That(result, Does.StartWith("?greeting=Hello%20")); + Assert.That(result, Does.Contain("%E4%B8%96%E7%95%8C")); // 世界 + } + + [Test] + public void Build_SessionSettings_DeepObject() + { + // Simulate session settings with nested properties + var sessionSettings = new + { + custom_session_id = "my-custom-session-id", + system_prompt = "You are a helpful assistant", + variables = new Dictionary + { + { "userName", "John" }, + { "userAge", 30 }, + { "isPremium", true }, + }, + }; + + // Build query parameters list + var queryParams = new List> { new("api_key", "test_key_123") }; + + // Add session_settings with prefix using the new overload + queryParams.AddRange( + QueryStringConverter.ToDeepObject("session_settings", sessionSettings) + ); + + var result = QueryStringBuilder.Build(queryParams); + + // Verify the result contains properly formatted deep object notation + // Note: Square brackets are URL-encoded as %5B and %5D + Assert.That(result, Does.StartWith("?api_key=test_key_123")); + Assert.That( + result, + Does.Contain("session_settings%5Bcustom_session_id%5D=my-custom-session-id") + ); + Assert.That( + result, + Does.Contain("session_settings%5Bsystem_prompt%5D=You%20are%20a%20helpful%20assistant") + ); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5BuserName%5D=John")); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5BuserAge%5D=30")); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5BisPremium%5D=true")); + + // Verify it's NOT JSON encoded (no braces or quotes in the original format) + Assert.That(result, Does.Not.Contain("%7B%22")); // Not {" sequence + } + + [Test] + public void Build_ChatApiLikeParameters() + { + // Simulate what ChatApi constructor does + var sessionSettings = new + { + system_prompt = "You are helpful", + variables = new Dictionary { { "name", "Alice" } }, + }; + + var queryParams = new List>(); + + // Simple parameters + var simpleParams = new Dictionary + { + { "access_token", "token123" }, + { "config_id", "config456" }, + { "api_key", "key789" }, + }; + queryParams.AddRange(QueryStringConverter.ToExplodedForm(simpleParams)); + + // Session settings as deep object with prefix + queryParams.AddRange( + QueryStringConverter.ToDeepObject("session_settings", sessionSettings) + ); + + var result = QueryStringBuilder.Build(queryParams); + + // Verify structure (square brackets are URL-encoded) + Assert.That(result, Does.StartWith("?")); + Assert.That(result, Does.Contain("access_token=token123")); + Assert.That(result, Does.Contain("config_id=config456")); + Assert.That(result, Does.Contain("api_key=key789")); + Assert.That( + result, + Does.Contain("session_settings%5Bsystem_prompt%5D=You%20are%20helpful") + ); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5Bname%5D=Alice")); + } + + [Test] + public void Build_ReservedCharacters_NotEncoded() + { + var parameters = new List> + { + new("path", "some-path"), + new("id", "123-456_789.test~value"), + }; + + var result = QueryStringBuilder.Build(parameters); + + // Safe query characters include RFC 3986 unreserved + sub-delimiters (except & = +) + : @ / + Assert.That(result, Is.EqualTo("?path=some-path&id=123-456_789.test~value")); + } + + [Test] + public void Builder_Add_SimpleParameters() + { + var result = new QueryStringBuilder.Builder() + .Add("name", "John Doe") + .Add("age", 30) + .Add("active", true) + .Build(); + + Assert.That(result, Does.Contain("name=John%20Doe")); + Assert.That(result, Does.Contain("age=30")); + Assert.That(result, Does.Contain("active=true")); + } + + [Test] + public void Builder_Add_NullValuesIgnored() + { + var result = new QueryStringBuilder.Builder() + .Add("name", "John") + .Add("middle", null) + .Add("age", 30) + .Build(); + + Assert.That(result, Does.Contain("name=John")); + Assert.That(result, Does.Contain("age=30")); + Assert.That(result, Does.Not.Contain("middle")); + } + + [Test] + public void Builder_AddDeepObject_WithPrefix() + { + var settings = new + { + custom_session_id = "id-123", + system_prompt = "You are helpful", + variables = new { name = "Alice", age = 25 }, + }; + + var result = new QueryStringBuilder.Builder() + .Add("api_key", "key123") + .AddDeepObject("session_settings", settings) + .Build(); + + Assert.That(result, Does.Contain("api_key=key123")); + Assert.That(result, Does.Contain("session_settings%5Bcustom_session_id%5D=id-123")); + Assert.That( + result, + Does.Contain("session_settings%5Bsystem_prompt%5D=You%20are%20helpful") + ); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5Bname%5D=Alice")); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5Bage%5D=25")); + } + + [Test] + public void Builder_AddDeepObject_NullIgnored() + { + var result = new QueryStringBuilder.Builder() + .Add("api_key", "key123") + .AddDeepObject("settings", null) + .Build(); + + Assert.That(result, Is.EqualTo("?api_key=key123")); + Assert.That(result, Does.Not.Contain("settings")); + } + + [Test] + public void Builder_AddExploded_WithPrefix() + { + var filter = new { status = "active", type = "user" }; + + var result = new QueryStringBuilder.Builder() + .Add("api_key", "key123") + .AddExploded("filter", filter) + .Build(); + + Assert.That(result, Does.Contain("api_key=key123")); + Assert.That(result, Does.Contain("filter%5Bstatus%5D=active")); + Assert.That(result, Does.Contain("filter%5Btype%5D=user")); + } + + [Test] + public void Builder_AddExploded_NullIgnored() + { + var result = new QueryStringBuilder.Builder() + .Add("api_key", "key123") + .AddExploded("filter", null) + .Build(); + + Assert.That(result, Is.EqualTo("?api_key=key123")); + Assert.That(result, Does.Not.Contain("filter")); + } + + [Test] + public void Builder_WithCapacity() + { + // Test that capacity constructor works without errors + var result = new QueryStringBuilder.Builder(capacity: 10) + .Add("param1", "value1") + .Add("param2", "value2") + .Build(); + + Assert.That(result, Does.Contain("param1=value1")); + Assert.That(result, Does.Contain("param2=value2")); + } + + [Test] + public void Builder_ChatApiLikeUsage() + { + // Simulate real usage from ChatApi + var sessionSettings = new + { + custom_session_id = "session-123", + variables = new Dictionary + { + { "userName", "John" }, + { "userAge", 30 }, + }, + }; + + var result = new QueryStringBuilder.Builder(capacity: 16) + .Add("access_token", "token123") + .Add("allow_connection", true) + .Add("config_id", "config456") + .Add("api_key", "key789") + .AddDeepObject("session_settings", sessionSettings) + .Build(); + + Assert.That(result, Does.StartWith("?")); + Assert.That(result, Does.Contain("access_token=token123")); + Assert.That(result, Does.Contain("allow_connection=true")); + Assert.That(result, Does.Contain("config_id=config456")); + Assert.That(result, Does.Contain("api_key=key789")); + Assert.That(result, Does.Contain("session_settings%5Bcustom_session_id%5D=session-123")); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5BuserName%5D=John")); + Assert.That(result, Does.Contain("session_settings%5Bvariables%5D%5BuserAge%5D=30")); + } + + [Test] + public void Builder_EmptyBuilder_ReturnsEmptyString() + { + var result = new QueryStringBuilder.Builder().Build(); + + Assert.That(result, Is.EqualTo(string.Empty)); + } + + [Test] + public void Builder_OnlyNullValues_ReturnsEmptyString() + { + var result = new QueryStringBuilder.Builder() + .Add("param1", null) + .Add("param2", null) + .AddDeepObject("settings", null) + .Build(); + + Assert.That(result, Is.EqualTo(string.Empty)); + } + + [Test] + public void Builder_Set_OverridesSingleValue() + { + var result = new QueryStringBuilder.Builder() + .Add("foo", "original") + .Set("foo", "override") + .Build(); + + Assert.That(result, Is.EqualTo("?foo=override")); + } + + [Test] + public void Builder_Set_OverridesMultipleValues() + { + var result = new QueryStringBuilder.Builder() + .Add("foo", "value1") + .Add("foo", "value2") + .Set("foo", "override") + .Build(); + + Assert.That(result, Is.EqualTo("?foo=override")); + } + + [Test] + public void Builder_Set_WithArray_CreatesMultipleParameters() + { + var result = new QueryStringBuilder.Builder() + .Add("foo", "original") + .Set("foo", new[] { "value1", "value2" }) + .Build(); + + Assert.That(result, Is.EqualTo("?foo=value1&foo=value2")); + } + + [Test] + public void Builder_Set_WithNull_RemovesParameter() + { + var result = new QueryStringBuilder.Builder() + .Add("foo", "original") + .Add("bar", "keep") + .Set("foo", null) + .Build(); + + Assert.That(result, Is.EqualTo("?bar=keep")); + } + + [Test] + public void Builder_MergeAdditional_WithSingleValues() + { + var additional = new List> + { + new("foo", "bar"), + new("baz", "qux"), + }; + + var result = new QueryStringBuilder.Builder() + .Add("existing", "value") + .MergeAdditional(additional) + .Build(); + + Assert.That(result, Does.Contain("existing=value")); + Assert.That(result, Does.Contain("foo=bar")); + Assert.That(result, Does.Contain("baz=qux")); + } + + [Test] + public void Builder_MergeAdditional_WithDuplicateKeys_CreatesList() + { + var additional = new List> + { + new("foo", "bar1"), + new("foo", "bar2"), + new("baz", "qux"), + }; + + var result = new QueryStringBuilder.Builder() + .Add("existing", "value") + .MergeAdditional(additional) + .Build(); + + Assert.That(result, Does.Contain("existing=value")); + Assert.That(result, Does.Contain("foo=bar1")); + Assert.That(result, Does.Contain("foo=bar2")); + Assert.That(result, Does.Contain("baz=qux")); + } + + [Test] + public void Builder_MergeAdditional_OverridesExistingParameters() + { + var additional = new List> { new("foo", "override") }; + + var result = new QueryStringBuilder.Builder() + .Add("foo", "original1") + .Add("foo", "original2") + .Add("bar", "keep") + .MergeAdditional(additional) + .Build(); + + Assert.That(result, Does.Contain("bar=keep")); + Assert.That(result, Does.Contain("foo=override")); + Assert.That(result, Does.Not.Contain("original1")); + Assert.That(result, Does.Not.Contain("original2")); + } + + [Test] + public void Builder_MergeAdditional_WithDuplicates_OverridesExisting() + { + var additional = new List> + { + new("foo", "new1"), + new("foo", "new2"), + new("foo", "new3"), + }; + + var result = new QueryStringBuilder.Builder() + .Add("foo", "original1") + .Add("foo", "original2") + .Add("bar", "keep") + .MergeAdditional(additional) + .Build(); + + Assert.That(result, Does.Contain("bar=keep")); + Assert.That(result, Does.Contain("foo=new1")); + Assert.That(result, Does.Contain("foo=new2")); + Assert.That(result, Does.Contain("foo=new3")); + Assert.That(result, Does.Not.Contain("original1")); + Assert.That(result, Does.Not.Contain("original2")); + } + + [Test] + public void Builder_MergeAdditional_WithNull_NoOp() + { + var result = new QueryStringBuilder.Builder() + .Add("foo", "value") + .MergeAdditional(null) + .Build(); + + Assert.That(result, Is.EqualTo("?foo=value")); + } + + [Test] + public void Builder_MergeAdditional_WithEmptyList_NoOp() + { + var additional = new List>(); + + var result = new QueryStringBuilder.Builder() + .Add("foo", "value") + .MergeAdditional(additional) + .Build(); + + Assert.That(result, Is.EqualTo("?foo=value")); + } + + [Test] + public void Builder_MergeAdditional_RealWorldScenario() + { + // SDK generates foo=foo1&foo=foo2 + var builder = new QueryStringBuilder.Builder() + .Add("foo", "foo1") + .Add("foo", "foo2") + .Add("bar", "baz"); + + // User provides foo=override in AdditionalQueryParameters + var additional = new List> { new("foo", "override") }; + + var result = builder.MergeAdditional(additional).Build(); + + // Result should be foo=override&bar=baz (user overrides SDK) + Assert.That(result, Does.Contain("bar=baz")); + Assert.That(result, Does.Contain("foo=override")); + Assert.That(result, Does.Not.Contain("foo1")); + Assert.That(result, Does.Not.Contain("foo2")); + } + + [Test] + public void Builder_MergeAdditional_UserProvidesMultipleValues() + { + // SDK generates no foo parameter + var builder = new QueryStringBuilder.Builder().Add("bar", "baz"); + + // User provides foo=bar1&foo=bar2 in AdditionalQueryParameters + var additional = new List> + { + new("foo", "bar1"), + new("foo", "bar2"), + }; + + var result = builder.MergeAdditional(additional).Build(); + + // Result should be bar=baz&foo=bar1&foo=bar2 + Assert.That(result, Does.Contain("bar=baz")); + Assert.That(result, Does.Contain("foo=bar1")); + Assert.That(result, Does.Contain("foo=bar2")); + } + + [Test] + public void Builder_Add_WithCollection_CreatesMultipleParameters() + { + var tags = new[] { "tag1", "tag2", "tag3" }; + var result = new QueryStringBuilder.Builder().Add("tag", tags).Build(); + + Assert.That(result, Does.Contain("tag=tag1")); + Assert.That(result, Does.Contain("tag=tag2")); + Assert.That(result, Does.Contain("tag=tag3")); + } + + [Test] + public void Builder_Add_WithList_CreatesMultipleParameters() + { + var ids = new List { 1, 2, 3 }; + var result = new QueryStringBuilder.Builder().Add("id", ids).Build(); + + Assert.That(result, Does.Contain("id=1")); + Assert.That(result, Does.Contain("id=2")); + Assert.That(result, Does.Contain("id=3")); + } + + [Test] + public void Builder_Set_WithCollection_ReplacesAllPreviousValues() + { + var result = new QueryStringBuilder.Builder() + .Add("id", 1) + .Add("id", 2) + .Set("id", new[] { 10, 20, 30 }) + .Build(); + + Assert.That(result, Does.Contain("id=10")); + Assert.That(result, Does.Contain("id=20")); + Assert.That(result, Does.Contain("id=30")); + // Check that old values are not present (use word boundaries to avoid false positives with id=10) + Assert.That(result, Does.Not.Contain("id=1&")); + Assert.That(result, Does.Not.Contain("id=2&")); + Assert.That(result, Does.Not.Contain("id=1?")); + Assert.That(result, Does.Not.Contain("id=2?")); + Assert.That(result, Does.Not.EndWith("id=1")); + Assert.That(result, Does.Not.EndWith("id=2")); + } + + [Test] + public void EncodePathSegment_UnreservedChars_NotEncoded() + { + var result = QueryStringBuilder.EncodePathSegment("hello-world_test.value~123"); + Assert.That(result, Is.EqualTo("hello-world_test.value~123")); + } + + [Test] + public void EncodePathSegment_SubDelimiters_NotEncoded() + { + // All sub-delimiters are safe in path segments per RFC 3986 + var result = QueryStringBuilder.EncodePathSegment("a!b$c&d'e(f)g*h+i,j;k=l"); + Assert.That(result, Is.EqualTo("a!b$c&d'e(f)g*h+i,j;k=l")); + } + + [Test] + public void EncodePathSegment_ColonAndAt_NotEncoded() + { + var result = QueryStringBuilder.EncodePathSegment("user@host:8080"); + Assert.That(result, Is.EqualTo("user@host:8080")); + } + + [Test] + public void EncodePathSegment_SlashAndQuestion_Encoded() + { + // "/" and "?" are NOT part of pchar, so they must be encoded in path segments + var result = QueryStringBuilder.EncodePathSegment("path/with?query"); + Assert.That(result, Is.EqualTo("path%2Fwith%3Fquery")); + } + + [Test] + public void EncodePathSegment_Space_Encoded() + { + var result = QueryStringBuilder.EncodePathSegment("hello world"); + Assert.That(result, Is.EqualTo("hello%20world")); + } + + [Test] + public void EncodePathSegment_EmptyAndNull() + { + Assert.That(QueryStringBuilder.EncodePathSegment(""), Is.EqualTo("")); + Assert.That(QueryStringBuilder.EncodePathSegment(null!), Is.Null); + } + + [Test] + public void Build_QueryKeyVsValue_DifferentEncoding() + { + // "=" is safe in query values but NOT in query keys + var parameters = new List> + { + new("key=with=equals", "value=with=equals"), + }; + + var result = QueryStringBuilder.Build(parameters); + + // Key: "=" must be encoded + // Value: "=" is safe (part of query value safe chars) + Assert.That(result, Is.EqualTo("?key%3Dwith%3Dequals=value=with=equals")); + } + + [Test] + public void Build_QueryValue_QuestionMarkNotEncoded() + { + // "?" is safe in both query keys and query values per RFC 3986 + var parameters = new List> { new("q?key", "is this?") }; + + var result = QueryStringBuilder.Build(parameters); + + Assert.That(result, Is.EqualTo("?q?key=is%20this?")); + } + + [Test] + public void Build_QueryKey_PlusEncoded() + { + // "+" must be encoded in both query keys and query values + var parameters = new List> { new("a+b", "c+d") }; + + var result = QueryStringBuilder.Build(parameters); + + Assert.That(result, Is.EqualTo("?a%2Bb=c%2Bd")); + } + + [Test] + public void Build_Semicolon_Encoded() + { + // ";" is a legacy parameter separator, so it must be encoded in keys and values + var parameters = new List> + { + new("a;b", "jo@example.com; ceo@example.com"), + }; + + var result = QueryStringBuilder.Build(parameters); + + Assert.That(result, Is.EqualTo("?a%3Bb=jo@example.com%3B%20ceo@example.com")); + } + + [Test] + public void Build_ODataFilter_DollarPreserved() + { + // "$" is safe in query keys (sub-delimiter), verifies OData-style parameters work + var parameters = new List> + { + new("$filter", "status eq 'active'"), + new("$top", "10"), + }; + + var result = QueryStringBuilder.Build(parameters); + + Assert.That(result, Does.Contain("$filter=status%20eq%20'active'")); + Assert.That(result, Does.Contain("$top=10")); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/QueryStringConverterTests.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/QueryStringConverterTests.cs new file mode 100644 index 000000000000..d73c8df94238 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/QueryStringConverterTests.cs @@ -0,0 +1,158 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core; + +[TestFixture] +public class QueryStringConverterTests +{ + [Test] + public void ToQueryStringCollection_Form() + { + var obj = new + { + Name = "John", + Age = 30, + Address = new + { + Street = "123 Main St", + City = "Anytown", + Coordinates = new[] { 39.781721f, -89.650148f }, + }, + Tags = new[] { "Developer", "Blogger" }, + }; + var result = QueryStringConverter.ToForm(obj); + var expected = new List> + { + new("Name", "John"), + new("Age", "30"), + new("Address[Street]", "123 Main St"), + new("Address[City]", "Anytown"), + new("Address[Coordinates]", "39.78172,-89.65015"), + new("Tags", "Developer,Blogger"), + }; + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void ToQueryStringCollection_ExplodedForm() + { + var obj = new + { + Name = "John", + Age = 30, + Address = new + { + Street = "123 Main St", + City = "Anytown", + Coordinates = new[] { 39.781721f, -89.650148f }, + }, + Tags = new[] { "Developer", "Blogger" }, + }; + var result = QueryStringConverter.ToExplodedForm(obj); + var expected = new List> + { + new("Name", "John"), + new("Age", "30"), + new("Address[Street]", "123 Main St"), + new("Address[City]", "Anytown"), + new("Address[Coordinates]", "39.78172"), + new("Address[Coordinates]", "-89.65015"), + new("Tags", "Developer"), + new("Tags", "Blogger"), + }; + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void ToQueryStringCollection_DeepObject() + { + var obj = new + { + Name = "John", + Age = 30, + Address = new + { + Street = "123 Main St", + City = "Anytown", + Coordinates = new[] { 39.781721f, -89.650148f }, + }, + Tags = new[] { "Developer", "Blogger" }, + }; + var result = QueryStringConverter.ToDeepObject(obj); + var expected = new List> + { + new("Name", "John"), + new("Age", "30"), + new("Address[Street]", "123 Main St"), + new("Address[City]", "Anytown"), + new("Address[Coordinates][0]", "39.78172"), + new("Address[Coordinates][1]", "-89.65015"), + new("Tags[0]", "Developer"), + new("Tags[1]", "Blogger"), + }; + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void ToQueryStringCollection_OnString_ThrowsException() + { + var exception = Assert.Throws(() => + QueryStringConverter.ToForm("invalid") + ); + Assert.That( + exception.Message, + Is.EqualTo( + "Only objects can be converted to query string collections. Given type is String." + ) + ); + } + + [Test] + public void ToQueryStringCollection_OnArray_ThrowsException() + { + var exception = Assert.Throws(() => + QueryStringConverter.ToForm(Array.Empty()) + ); + Assert.That( + exception.Message, + Is.EqualTo( + "Only objects can be converted to query string collections. Given type is Array." + ) + ); + } + + [Test] + public void ToQueryStringCollection_DeepObject_WithPrefix() + { + var obj = new + { + custom_session_id = "my-id", + system_prompt = "You are helpful", + variables = new { name = "Alice", age = 25 }, + }; + var result = QueryStringConverter.ToDeepObject("session_settings", obj); + var expected = new List> + { + new("session_settings[custom_session_id]", "my-id"), + new("session_settings[system_prompt]", "You are helpful"), + new("session_settings[variables][name]", "Alice"), + new("session_settings[variables][age]", "25"), + }; + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void ToQueryStringCollection_ExplodedForm_WithPrefix() + { + var obj = new { Name = "John", Tags = new[] { "Developer", "Blogger" } }; + var result = QueryStringConverter.ToExplodedForm("user", obj); + var expected = new List> + { + new("user[Name]", "John"), + new("user[Tags]", "Developer"), + new("user[Tags]", "Blogger"), + }; + Assert.That(result, Is.EqualTo(expected)); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/GzipResponseTests.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/GzipResponseTests.cs new file mode 100644 index 000000000000..d3530f3708b1 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/GzipResponseTests.cs @@ -0,0 +1,104 @@ +using global::System.IO.Compression; +using global::System.Net.Http; +using global::System.Text; +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; +using WireMock.Server; +using SystemTask = global::System.Threading.Tasks.Task; +using WireMockRequest = WireMock.RequestBuilders.Request; +using WireMockResponse = WireMock.ResponseBuilders.Response; + +namespace SeedCsharpXmlEntities.Test.Core.RawClientTests; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class GzipResponseTests +{ + private WireMockServer _server; + private RawClient _rawClient; + private string _baseUrl; + + [SetUp] + public void SetUp() + { + _server = WireMockServer.Start(); + _baseUrl = _server.Url ?? ""; + _rawClient = new RawClient(new ClientOptions { MaxRetries = 0 }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldDecompressGzipResponse() + { + const string body = "{\"message\": \"gzipped response\"}"; + _server + .Given( + WireMockRequest + .Create() + .WithPath("/gzip") + .WithHeader("Accept-Encoding", "gzip*") + .UsingGet() + ) + .RespondWith( + WireMockResponse + .Create() + .WithStatusCode(200) + .WithHeader("Content-Encoding", "gzip") + .WithBody(Compress(body)) + ); + + var request = new SeedCsharpXmlEntities.Core.EmptyRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/gzip", + Headers = new Dictionary { ["Accept-Encoding"] = "gzip" }, + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.That(content, Is.EqualTo(body)); + Assert.That(response.Raw.Content.Headers.ContentEncoding, Is.Empty); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldReturnUncompressedResponseUnchanged() + { + const string body = "{\"message\": \"plain response\"}"; + _server + .Given(WireMockRequest.Create().WithPath("/plain").UsingGet()) + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody(body)); + + var request = new SeedCsharpXmlEntities.Core.EmptyRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/plain", + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.That(content, Is.EqualTo(body)); + } + + private static byte[] Compress(string value) + { + using var output = new MemoryStream(); + using (var gzipStream = new GZipStream(output, CompressionMode.Compress)) + { + var bytes = Encoding.UTF8.GetBytes(value); + gzipStream.Write(bytes, 0, bytes.Length); + } + return output.ToArray(); + } + + [TearDown] + public void TearDown() + { + _server.Stop(); + _server.Dispose(); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/MultipartFormTests.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/MultipartFormTests.cs new file mode 100644 index 000000000000..bf44cacdf0a2 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/MultipartFormTests.cs @@ -0,0 +1,1121 @@ +using global::System.Net.Http; +using global::System.Text; +using global::System.Text.Json.Serialization; +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; +using SystemTask = global::System.Threading.Tasks.Task; + +namespace SeedCsharpXmlEntities.Test.Core.RawClientTests; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class MultipartFormTests +{ + private static SimpleObject _simpleObject = new(); + + private static string _simpleFormEncoded = + "meta=data&Date=2023-10-01&Time=12:00:00&Duration=01:00:00&Id=1a1bb98f-47c6-407b-9481-78476affe52a&IsActive=true&Count=42&Initial=A&Values=data,2023-10-01,12:00:00,01:00:00,1a1bb98f-47c6-407b-9481-78476affe52a,true,42,A"; + + private static string _simpleExplodedFormEncoded = + "meta=data&Date=2023-10-01&Time=12:00:00&Duration=01:00:00&Id=1a1bb98f-47c6-407b-9481-78476affe52a&IsActive=true&Count=42&Initial=A&Values=data&Values=2023-10-01&Values=12:00:00&Values=01:00:00&Values=1a1bb98f-47c6-407b-9481-78476affe52a&Values=true&Values=42&Values=A"; + + private static ComplexObject _complexObject = new(); + + private static string _complexJson = """ + { + "meta": "data", + "Nested": { + "foo": "value" + }, + "NestedDictionary": { + "key": { + "foo": "value" + } + }, + "ListOfObjects": [ + { + "foo": "value" + }, + { + "foo": "value2" + } + ], + "Date": "2023-10-01", + "Time": "12:00:00", + "Duration": "01:00:00", + "Id": "1a1bb98f-47c6-407b-9481-78476affe52a", + "IsActive": true, + "Count": 42, + "Initial": "A" + } + """; + + [Test] + public async SystemTask ShouldAddStringPart() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringPart("string", partInput); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=string + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddStringParts() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringParts("strings", [partInput, partInput]); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask GivenNull_ShouldNotAddStringPart() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringPart("string", null); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddStringParts_WithNullsInList() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringParts("strings", [partInput, null, partInput]); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddStringPart_WithContentType() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringPart("string", partInput, "text/xml"); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/xml + Content-Disposition: form-data; name=string + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddStringPart_WithContentTypeAndCharset() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringPart("string", partInput, "text/xml; charset=utf-8"); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/xml; charset=utf-8 + Content-Disposition: form-data; name=string + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddStringParts_WithContentType() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringParts("strings", [partInput, partInput], "text/xml"); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/xml + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary} + Content-Type: text/xml + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddStringParts_WithContentTypeAndCharset() + { + const string partInput = "string content"; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddStringParts( + "strings", + [partInput, partInput], + "text/xml; charset=utf-8" + ); + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/xml; charset=utf-8 + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary} + Content-Type: text/xml; charset=utf-8 + Content-Disposition: form-data; name=strings + + {partInput} + --{boundary}-- + """; + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameter_WithFileName() + { + var (partInput, partExpectedString) = GetFileParameterTestData(); + var file = new FileParameter { Stream = partInput, FileName = "test.txt" }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", file); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/octet-stream + Content-Disposition: form-data; name=file; filename=test.txt; filename*=utf-8''test.txt + + {partExpectedString} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameter_WithoutFileName() + { + var (partInput, partExpectedString) = GetFileParameterTestData(); + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", partInput); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/octet-stream + Content-Disposition: form-data; name=file + + {partExpectedString} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameter_WithContentType() + { + var (partInput, partExpectedString) = GetFileParameterTestData(); + var file = new FileParameter + { + Stream = partInput, + FileName = "test.txt", + ContentType = "text/plain", + }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", file, "ignored-fallback-content-type"); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=file; filename=test.txt; filename*=utf-8''test.txt + + {partExpectedString} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameter_WithContentTypeAndCharset() + { + var (partInput, partExpectedString) = GetFileParameterTestData(); + var file = new FileParameter + { + Stream = partInput, + FileName = "test.txt", + ContentType = "text/plain; charset=utf-8", + }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", file, "ignored-fallback-content-type"); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain; charset=utf-8 + Content-Disposition: form-data; name=file; filename=test.txt; filename*=utf-8''test.txt + + {partExpectedString} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameter_WithFallbackContentType() + { + var (partInput, partExpectedString) = GetFileParameterTestData(); + var file = new FileParameter { Stream = partInput, FileName = "test.txt" }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", file, "text/plain"); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain + Content-Disposition: form-data; name=file; filename=test.txt; filename*=utf-8''test.txt + + {partExpectedString} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameter_WithFallbackContentTypeAndCharset() + { + var (partInput, partExpectedString) = GetFileParameterTestData(); + var file = new FileParameter { Stream = partInput, FileName = "test.txt" }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", file, "text/plain; charset=utf-8"); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: text/plain; charset=utf-8 + Content-Disposition: form-data; name=file; filename=test.txt; filename*=utf-8''test.txt + + {partExpectedString} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameters() + { + var (partInput1, partExpectedString1) = GetFileParameterTestData(); + var (partInput2, partExpectedString2) = GetFileParameterTestData(); + var file1 = new FileParameter { Stream = partInput1, FileName = "test1.txt" }; + var file2 = new FileParameter { Stream = partInput2, FileName = "test2.txt" }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterParts("file", [file1, file2]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/octet-stream + Content-Disposition: form-data; name=file; filename=test1.txt; filename*=utf-8''test1.txt + + {partExpectedString1} + --{boundary} + Content-Type: application/octet-stream + Content-Disposition: form-data; name=file; filename=test2.txt; filename*=utf-8''test2.txt + + {partExpectedString2} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFileParameters_WithNullsInList() + { + var (partInput1, partExpectedString1) = GetFileParameterTestData(); + var (partInput2, partExpectedString2) = GetFileParameterTestData(); + var file1 = new FileParameter { Stream = partInput1, FileName = "test1.txt" }; + var file2 = new FileParameter { Stream = partInput2, FileName = "test2.txt" }; + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterParts("file", [file1, null, file2]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/octet-stream + Content-Disposition: form-data; name=file; filename=test1.txt; filename*=utf-8''test1.txt + + {partExpectedString1} + --{boundary} + Content-Type: application/octet-stream + Content-Disposition: form-data; name=file; filename=test2.txt; filename*=utf-8''test2.txt + + {partExpectedString2} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask GivenNull_ShouldNotAddFileParameter() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFileParameterPart("file", null); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddJsonPart_WithComplexObject() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddJsonPart("object", _complexObject); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/json + Content-Disposition: form-data; name=object + + {_complexJson} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddJsonPart_WithComplexObjectList() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddJsonParts("objects", [_complexObject, _complexObject]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/json + Content-Disposition: form-data; name=objects + + {_complexJson} + --{boundary} + Content-Type: application/json + Content-Disposition: form-data; name=objects + + {_complexJson} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask GivenNull_ShouldNotAddJsonPart() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddJsonPart("object", null); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddJsonParts_WithNullsInList() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddJsonParts("objects", [_complexObject, null]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/json + Content-Disposition: form-data; name=objects + + {_complexJson} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddJsonParts_WithContentType() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddJsonParts("objects", [new { }], "application/json-patch+json"); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $$""" + --{{boundary}} + Content-Type: application/json-patch+json + Content-Disposition: form-data; name=objects + + {} + --{{boundary}}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFormEncodedParts_WithSimpleObject() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedPart("object", _simpleObject); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=object + + {EscapeFormEncodedString(_simpleFormEncoded)} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFormEncodedParts_WithSimpleObjectList() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedParts("objects", [_simpleObject, _simpleObject]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + {EscapeFormEncodedString(_simpleFormEncoded)} + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + {EscapeFormEncodedString(_simpleFormEncoded)} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldNotAddFormEncodedParts_WithNull() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedParts("object", null); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldNotAddFormEncodedParts_WithNullsInList() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedParts("objects", [_simpleObject, null]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + {EscapeFormEncodedString(_simpleFormEncoded)} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFormEncodedPart_WithContentType() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedPart( + "objects", + new { foo = "bar" }, + "application/x-www-form-urlencoded" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFormEncodedPart_WithContentTypeAndCharset() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedPart( + "objects", + new { foo = "bar" }, + "application/x-www-form-urlencoded; charset=utf-8" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded; charset=utf-8 + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFormEncodedParts_WithContentType() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedParts( + "objects", + [new { foo = "bar" }], + "application/x-www-form-urlencoded" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddFormEncodedParts_WithContentTypeAndCharset() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddFormEncodedParts( + "objects", + [new { foo = "bar" }], + "application/x-www-form-urlencoded; charset=utf-8" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded; charset=utf-8 + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddExplodedFormEncodedParts_WithSimpleObject() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedPart("object", _simpleObject); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=object + + {EscapeFormEncodedString(_simpleExplodedFormEncoded)} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddExplodedFormEncodedParts_WithSimpleObjectList() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedParts("objects", [_simpleObject, _simpleObject]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + {EscapeFormEncodedString(_simpleExplodedFormEncoded)} + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + {EscapeFormEncodedString(_simpleExplodedFormEncoded)} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldNotAddExplodedFormEncodedParts_WithNull() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedPart("object", null); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldNotAddExplodedFormEncodedParts_WithNullsInList() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedParts("objects", [_simpleObject, null]); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + {EscapeFormEncodedString(_simpleExplodedFormEncoded)} + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddExplodedFormEncodedPart_WithContentType() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedPart( + "objects", + new { foo = "bar" }, + "application/x-www-form-urlencoded" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddExplodedFormEncodedPart_WithContentTypeAndCharset() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedPart( + "objects", + new { foo = "bar" }, + "application/x-www-form-urlencoded; charset=utf-8" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded; charset=utf-8 + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddExplodedFormEncodedParts_WithContentType() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedParts( + "objects", + [new { foo = "bar" }], + "application/x-www-form-urlencoded" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + [Test] + public async SystemTask ShouldAddExplodedFormEncodedParts_WithContentTypeAndCharset() + { + var multipartFormRequest = CreateMultipartFormRequest(); + multipartFormRequest.AddExplodedFormEncodedParts( + "objects", + [new { foo = "bar" }], + "application/x-www-form-urlencoded; charset=utf-8" + ); + + var httpContent = multipartFormRequest.CreateContent(); + Assert.That(httpContent, Is.InstanceOf()); + var multipartContent = (MultipartFormDataContent)httpContent; + + var boundary = GetBoundary(multipartContent); + var expected = $""" + --{boundary} + Content-Type: application/x-www-form-urlencoded; charset=utf-8 + Content-Disposition: form-data; name=objects + + foo=bar + --{boundary}-- + """; + + var actual = await multipartContent.ReadAsStringAsync(); + Assert.That(actual, Is.EqualTo(expected).IgnoreWhiteSpace); + } + + private static string EscapeFormEncodedString(string input) + { + return string.Join( + "&", + input + .Split('&') + .Select(x => x.Split('=')) + .Select(x => $"{Uri.EscapeDataString(x[0])}={Uri.EscapeDataString(x[1])}") + ); + } + + private static string GetBoundary(MultipartFormDataContent content) + { + return content + .Headers.ContentType?.Parameters.Single(p => + p.Name.Equals("boundary", StringComparison.OrdinalIgnoreCase) + ) + .Value?.Trim('"') + ?? throw new global::System.Exception("Boundary not found"); + } + + private static SeedCsharpXmlEntities.Core.MultipartFormRequest CreateMultipartFormRequest() + { + return new SeedCsharpXmlEntities.Core.MultipartFormRequest + { + BaseUrl = "https://localhost", + Method = HttpMethod.Post, + Path = "", + }; + } + + private static (Stream partInput, string partExpectedString) GetFileParameterTestData() + { + const string partExpectedString = "file content"; + var partInput = new MemoryStream(Encoding.Default.GetBytes(partExpectedString)); + return (partInput, partExpectedString); + } + + private class SimpleObject + { + [JsonPropertyName("meta")] + public string Meta { get; set; } = "data"; + public DateOnly Date { get; set; } = DateOnly.Parse("2023-10-01"); + public TimeOnly Time { get; set; } = TimeOnly.Parse("12:00:00"); + public TimeSpan Duration { get; set; } = TimeSpan.FromHours(1); + public Guid Id { get; set; } = Guid.Parse("1a1bb98f-47c6-407b-9481-78476affe52a"); + public bool IsActive { get; set; } = true; + public int Count { get; set; } = 42; + public char Initial { get; set; } = 'A'; + public IEnumerable Values { get; set; } = + [ + "data", + DateOnly.Parse("2023-10-01"), + TimeOnly.Parse("12:00:00"), + TimeSpan.FromHours(1), + Guid.Parse("1a1bb98f-47c6-407b-9481-78476affe52a"), + true, + 42, + 'A', + ]; + } + + private class ComplexObject + { + [JsonPropertyName("meta")] + public string Meta { get; set; } = "data"; + + public object Nested { get; set; } = new { foo = "value" }; + + public Dictionary NestedDictionary { get; set; } = + new() { { "key", new { foo = "value" } } }; + + public IEnumerable ListOfObjects { get; set; } = + new List { new { foo = "value" }, new { foo = "value2" } }; + + public DateOnly Date { get; set; } = DateOnly.Parse("2023-10-01"); + public TimeOnly Time { get; set; } = TimeOnly.Parse("12:00:00"); + public TimeSpan Duration { get; set; } = TimeSpan.FromHours(1); + public Guid Id { get; set; } = Guid.Parse("1a1bb98f-47c6-407b-9481-78476affe52a"); + public bool IsActive { get; set; } = true; + public int Count { get; set; } = 42; + public char Initial { get; set; } = 'A'; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/QueryParameterTests.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/QueryParameterTests.cs new file mode 100644 index 000000000000..fb84851bc98a --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/QueryParameterTests.cs @@ -0,0 +1,108 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core.RawClientTests; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class QueryParameterTests +{ + [Test] + public void QueryParameters_BasicParameters() + { + var queryString = new QueryStringBuilder.Builder() + .Add("foo", "bar") + .Add("baz", "qux") + .Build(); + + Assert.That(queryString, Is.EqualTo("?foo=bar&baz=qux")); + } + + [Test] + public void QueryParameters_SpecialCharacterEscaping() + { + var queryString = new QueryStringBuilder.Builder() + .Add("email", "bob+test@example.com") + .Add("%Complete", "100") + .Add("space test", "hello world") + .Build(); + + Assert.That(queryString, Does.Contain("email=bob%2Btest@example.com")); + Assert.That(queryString, Does.Contain("%25Complete=100")); + Assert.That(queryString, Does.Contain("space%20test=hello%20world")); + } + + [Test] + public void QueryParameters_MergeAdditionalParameters() + { + var queryString = new QueryStringBuilder.Builder() + .Add("sdk", "param") + .MergeAdditional(new List> { new("user", "value") }) + .Build(); + + Assert.That(queryString, Does.Contain("sdk=param")); + Assert.That(queryString, Does.Contain("user=value")); + } + + [Test] + public void QueryParameters_AdditionalOverridesSdk() + { + var queryString = new QueryStringBuilder.Builder() + .Add("foo", "sdk_value") + .MergeAdditional(new List> { new("foo", "user_override") }) + .Build(); + + Assert.That(queryString, Does.Contain("foo=user_override")); + Assert.That(queryString, Does.Not.Contain("sdk_value")); + } + + [Test] + public void QueryParameters_AdditionalMultipleValues() + { + var queryString = new QueryStringBuilder.Builder() + .Add("foo", "sdk_value") + .MergeAdditional( + new List> { new("foo", "user1"), new("foo", "user2") } + ) + .Build(); + + Assert.That(queryString, Does.Contain("foo=user1")); + Assert.That(queryString, Does.Contain("foo=user2")); + Assert.That(queryString, Does.Not.Contain("sdk_value")); + } + + [Test] + public void QueryParameters_OnlyAdditionalParameters() + { + var queryString = new QueryStringBuilder.Builder() + .MergeAdditional( + new List> { new("foo", "bar"), new("baz", "qux") } + ) + .Build(); + + Assert.That(queryString, Does.Contain("foo=bar")); + Assert.That(queryString, Does.Contain("baz=qux")); + } + + [Test] + public void QueryParameters_EmptyAdditionalParameters() + { + var queryString = new QueryStringBuilder.Builder() + .Add("foo", "bar") + .MergeAdditional(new List>()) + .Build(); + + Assert.That(queryString, Is.EqualTo("?foo=bar")); + } + + [Test] + public void QueryParameters_NullAdditionalParameters() + { + var queryString = new QueryStringBuilder.Builder() + .Add("foo", "bar") + .MergeAdditional(null) + .Build(); + + Assert.That(queryString, Is.EqualTo("?foo=bar")); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/RetriesTests.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/RetriesTests.cs new file mode 100644 index 000000000000..99bd5a2ae53d --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/RawClientTests/RetriesTests.cs @@ -0,0 +1,540 @@ +using global::System.Net.Http; +using global::System.Text.Json; +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; +using WireMock.Server; +using SystemTask = global::System.Threading.Tasks.Task; +using WireMockRequest = WireMock.RequestBuilders.Request; +using WireMockResponse = WireMock.ResponseBuilders.Response; + +namespace SeedCsharpXmlEntities.Test.Core.RawClientTests; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class RetriesTests +{ + private const int MaxRetries = 3; + private WireMockServer _server; + private HttpClient _httpClient; + private RawClient _rawClient; + private string _baseUrl; + + [SetUp] + public void SetUp() + { + _server = WireMockServer.Start(); + _baseUrl = _server.Url ?? ""; + _httpClient = new HttpClient { BaseAddress = new Uri(_baseUrl) }; + _rawClient = new RawClient( + new ClientOptions { HttpClient = _httpClient, MaxRetries = MaxRetries } + ) + { + BaseRetryDelay = 0, + }; + } + + [Test] + [TestCase(408)] + [TestCase(429)] + [TestCase(500)] + [TestCase(504)] + public async SystemTask SendRequestAsync_ShouldRetry_OnRetryableStatusCodes(int statusCode) + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("Retry") + .WillSetStateTo("Server Error") + .RespondWith(WireMockResponse.Create().WithStatusCode(statusCode)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("Retry") + .WhenStateIs("Server Error") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(statusCode)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("Retry") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.EmptyRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/test", + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + using (Assert.EnterMultipleScope()) + { + Assert.That(content, Is.EqualTo("Success")); + + Assert.That(_server.LogEntries, Has.Count.EqualTo(MaxRetries)); + } + } + + [Test] + [TestCase(400)] + [TestCase(409)] + public async SystemTask SendRequestAsync_ShouldRetry_OnNonRetryableStatusCodes(int statusCode) + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("Retry") + .WillSetStateTo("Server Error") + .RespondWith(WireMockResponse.Create().WithStatusCode(statusCode).WithBody("Failure")); + + var request = new SeedCsharpXmlEntities.Core.JsonRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/test", + Body = new { }, + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(statusCode)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Failure")); + + Assert.That(_server.LogEntries, Has.Count.EqualTo(1)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldNotRetry_WithStreamRequest() + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("Retry") + .WillSetStateTo("Server Error") + .RespondWith(WireMockResponse.Create().WithStatusCode(429).WithBody("Failure")); + + var request = new SeedCsharpXmlEntities.Core.StreamRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + Body = new MemoryStream(), + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(429)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Failure")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(1)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldNotRetry_WithMultiPartFormRequest_WithStream() + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("Retry") + .WillSetStateTo("Server Error") + .RespondWith(WireMockResponse.Create().WithStatusCode(429).WithBody("Failure")); + + var request = new SeedCsharpXmlEntities.Core.MultipartFormRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + }; + request.AddFileParameterPart("file", new MemoryStream()); + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(429)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Failure")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(1)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldRetry_WithMultiPartFormRequest_WithoutStream() + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("Retry") + .WillSetStateTo("Server Error") + .RespondWith(WireMockResponse.Create().WithStatusCode(429)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("Retry") + .WhenStateIs("Server Error") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(429)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("Retry") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.MultipartFormRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + }; + request.AddJsonPart("object", new { }); + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(MaxRetries)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldRespectRetryAfterHeader_WithSecondsValue() + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("RetryAfter") + .WillSetStateTo("Success") + .RespondWith( + WireMockResponse.Create().WithStatusCode(429).WithHeader("Retry-After", "1") + ); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("RetryAfter") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.EmptyRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/test", + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(2)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldRespectRetryAfterHeader_WithHttpDateValue() + { + var retryAfterDate = DateTimeOffset.UtcNow.AddSeconds(1).ToString("R"); + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("RetryAfterDate") + .WillSetStateTo("Success") + .RespondWith( + WireMockResponse + .Create() + .WithStatusCode(429) + .WithHeader("Retry-After", retryAfterDate) + ); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("RetryAfterDate") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.EmptyRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/test", + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(2)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldRespectXRateLimitResetHeader() + { + var resetTime = DateTimeOffset.UtcNow.AddSeconds(1).ToUnixTimeSeconds().ToString(); + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("RateLimitReset") + .WillSetStateTo("Success") + .RespondWith( + WireMockResponse + .Create() + .WithStatusCode(429) + .WithHeader("X-RateLimit-Reset", resetTime) + ); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("RateLimitReset") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.EmptyRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/test", + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.Multiple(() => + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(2)); + }); + } + + [Test] + public async SystemTask SendRequestAsync_ShouldPreserveJsonBody_OnRetry() + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("RetryWithBody") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(500)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("RetryWithBody") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.JsonRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + Body = new { key = "value" }, + }; + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + using (Assert.EnterMultipleScope()) + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(2)); + + // Verify the retried request preserved the JSON body (compare parsed to ignore formatting differences) + var retriedEntry = _server.LogEntries.ElementAt(1); + using var actualJson = JsonDocument.Parse(retriedEntry.RequestMessage.Body!); + Assert.That(actualJson.RootElement.GetProperty("key").GetString(), Is.EqualTo("value")); + } + } + + [Test] + public async SystemTask SendRequestAsync_ShouldPreserveMultipartBody_OnRetry() + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("RetryMultipart") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(500)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("RetryMultipart") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new SeedCsharpXmlEntities.Core.MultipartFormRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + }; + request.AddJsonPart("object", new { key = "value" }); + + var response = await _rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + using (Assert.EnterMultipleScope()) + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(2)); + + // Verify the retried request preserved the multipart body (check key/value presence to ignore formatting differences) + var retriedEntry = _server.LogEntries.ElementAt(1); + Assert.That(retriedEntry.RequestMessage.Body, Does.Contain("\"key\"")); + Assert.That(retriedEntry.RequestMessage.Body, Does.Contain("\"value\"")); + } + } + + [Test] + public async SystemTask SendRequestAsync_ShouldRetry_WhenHandlerDisposesRequestContent() + { + // ContentDisposingHandler simulates HTTP/2's disposal of request.Content after send; + // WireMock's loopback HTTP/1.1 path does not exhibit that on its own. + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("DisposeContentRetry") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(500)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("DisposeContentRetry") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + using var disposingClient = new HttpClient( + new ContentDisposingHandler(new HttpClientHandler()) + ); + var rawClient = new RawClient( + new ClientOptions { HttpClient = disposingClient, MaxRetries = MaxRetries } + ) + { + BaseRetryDelay = 0, + }; + + var request = new SeedCsharpXmlEntities.Core.JsonRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + Body = new { key = "value" }, + }; + + var response = await rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + using (Assert.EnterMultipleScope()) + { + Assert.That(content, Is.EqualTo("Success")); + Assert.That(_server.LogEntries, Has.Count.EqualTo(2)); + + var retriedEntry = _server.LogEntries.ElementAt(1); + using var actualJson = JsonDocument.Parse(retriedEntry.RequestMessage.Body!); + Assert.That(actualJson.RootElement.GetProperty("key").GetString(), Is.EqualTo("value")); + } + } + + [Test] + public async SystemTask SendRequestAsync_ShouldRetry_WhenHandlerDisposesRequestContent_AcrossMultipleRetries() + { + // Exercises 2nd and 3rd clones — the single-retry variant can pass if those break. + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("DisposeContentMultiRetry") + .WillSetStateTo("Second") + .RespondWith(WireMockResponse.Create().WithStatusCode(500)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("DisposeContentMultiRetry") + .WhenStateIs("Second") + .WillSetStateTo("Third") + .RespondWith(WireMockResponse.Create().WithStatusCode(500)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("DisposeContentMultiRetry") + .WhenStateIs("Third") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(500)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingPost()) + .InScenario("DisposeContentMultiRetry") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + using var disposingClient = new HttpClient( + new ContentDisposingHandler(new HttpClientHandler()) + ); + var rawClient = new RawClient( + new ClientOptions { HttpClient = disposingClient, MaxRetries = MaxRetries } + ) + { + BaseRetryDelay = 0, + }; + + var request = new SeedCsharpXmlEntities.Core.JsonRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Post, + Path = "/test", + Body = new { key = "value" }, + }; + + var response = await rawClient.SendRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + using (Assert.EnterMultipleScope()) + { + // Initial attempt + 3 retries == 4 requests reaching the server. + Assert.That(_server.LogEntries, Has.Count.EqualTo(MaxRetries + 1)); + + // Every retried request must have preserved the original body. + foreach (var entry in _server.LogEntries) + { + using var actualJson = JsonDocument.Parse(entry.RequestMessage.Body!); + Assert.That( + actualJson.RootElement.GetProperty("key").GetString(), + Is.EqualTo("value") + ); + } + } + } + + [TearDown] + public void TearDown() + { + _server.Dispose(); + _httpClient.Dispose(); + } + + private sealed class ContentDisposingHandler : DelegatingHandler + { + public ContentDisposingHandler(HttpMessageHandler inner) + : base(inner) { } + + protected override async global::System.Threading.Tasks.Task SendAsync( + HttpRequestMessage request, + CancellationToken cancellationToken + ) + { + var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false); + request.Content?.Dispose(); + return response; + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/WithRawResponseTests.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/WithRawResponseTests.cs new file mode 100644 index 000000000000..355677943b0c --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Core/WithRawResponseTests.cs @@ -0,0 +1,269 @@ +using global::System.Net; +using global::System.Net.Http.Headers; +using NUnit.Framework; +using SeedCsharpXmlEntities; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Core; + +[TestFixture] +public class WithRawResponseTests +{ + [Test] + public async global::System.Threading.Tasks.Task WithRawResponseTask_DirectAwait_ReturnsData() + { + // Arrange + var expectedData = "test-data"; + var task = CreateWithRawResponseTask(expectedData, HttpStatusCode.OK); + + // Act + var result = await task; + + // Assert + Assert.That(result, Is.EqualTo(expectedData)); + } + + [Test] + public async global::System.Threading.Tasks.Task WithRawResponseTask_WithRawResponse_ReturnsDataAndMetadata() + { + // Arrange + var expectedData = "test-data"; + var expectedStatusCode = HttpStatusCode.Created; + var task = CreateWithRawResponseTask(expectedData, expectedStatusCode); + + // Act + var result = await task.WithRawResponse(); + + // Assert + Assert.That(result.Data, Is.EqualTo(expectedData)); + Assert.That(result.RawResponse.StatusCode, Is.EqualTo(expectedStatusCode)); + Assert.That(result.RawResponse.Url, Is.Not.Null); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_TryGetValue_CaseInsensitive() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + response.Headers.Add("X-Request-Id", "12345"); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act & Assert + Assert.That(headers.TryGetValue("X-Request-Id", out var value), Is.True); + Assert.That(value, Is.EqualTo("12345")); + + Assert.That(headers.TryGetValue("x-request-id", out value), Is.True); + Assert.That(value, Is.EqualTo("12345")); + + Assert.That(headers.TryGetValue("X-REQUEST-ID", out value), Is.True); + Assert.That(value, Is.EqualTo("12345")); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_TryGetValues_ReturnsMultipleValues() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + response.Headers.Add("Set-Cookie", new[] { "cookie1=value1", "cookie2=value2" }); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act + var success = headers.TryGetValues("Set-Cookie", out var values); + + // Assert + Assert.That(success, Is.True); + Assert.That(values, Is.Not.Null); + Assert.That(values!.Count(), Is.EqualTo(2)); + Assert.That(values, Does.Contain("cookie1=value1")); + Assert.That(values, Does.Contain("cookie2=value2")); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_ContentType_ReturnsValue() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + response.Content = new StringContent( + "{}", + global::System.Text.Encoding.UTF8, + "application/json" + ); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act + var contentType = headers.ContentType; + + // Assert + Assert.That(contentType, Is.Not.Null); + Assert.That(contentType, Does.Contain("application/json")); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_ContentLength_ReturnsValue() + { + // Arrange + var content = "test content"; + using var response = CreateHttpResponse(HttpStatusCode.OK); + response.Content = new StringContent(content); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act + var contentLength = headers.ContentLength; + + // Assert + Assert.That(contentLength, Is.Not.Null); + Assert.That(contentLength, Is.GreaterThan(0)); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_Contains_ReturnsTrueForExistingHeader() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + response.Headers.Add("X-Custom-Header", "value"); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act & Assert + Assert.That(headers.Contains("X-Custom-Header"), Is.True); + Assert.That(headers.Contains("x-custom-header"), Is.True); + Assert.That(headers.Contains("NonExistent"), Is.False); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_Enumeration_IncludesAllHeaders() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + response.Headers.Add("X-Header-1", "value1"); + response.Headers.Add("X-Header-2", "value2"); + response.Content = new StringContent("test"); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act + var allHeaders = headers.ToList(); + + // Assert + Assert.That(allHeaders.Count, Is.GreaterThan(0)); + Assert.That(allHeaders.Any(h => h.Name == "X-Header-1"), Is.True); + Assert.That(allHeaders.Any(h => h.Name == "X-Header-2"), Is.True); + } + + [Test] + public async global::System.Threading.Tasks.Task WithRawResponseTask_ErrorStatusCode_StillReturnsMetadata() + { + // Arrange + var expectedData = "error-data"; + var task = CreateWithRawResponseTask(expectedData, HttpStatusCode.BadRequest); + + // Act + var result = await task.WithRawResponse(); + + // Assert + Assert.That(result.Data, Is.EqualTo(expectedData)); + Assert.That(result.RawResponse.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest)); + } + + [Test] + public async global::System.Threading.Tasks.Task WithRawResponseTask_Url_IsPreserved() + { + // Arrange + var expectedUrl = new Uri("https://api.example.com/users/123"); + var task = CreateWithRawResponseTask("data", HttpStatusCode.OK, expectedUrl); + + // Act + var result = await task.WithRawResponse(); + + // Assert + Assert.That(result.RawResponse.Url, Is.EqualTo(expectedUrl)); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_TryGetValue_NonExistentHeader_ReturnsFalse() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act + var success = headers.TryGetValue("X-NonExistent", out var value); + + // Assert + Assert.That(success, Is.False); + Assert.That(value, Is.Null); + } + + [Test] + public async global::System.Threading.Tasks.Task ResponseHeaders_TryGetValues_NonExistentHeader_ReturnsFalse() + { + // Arrange + using var response = CreateHttpResponse(HttpStatusCode.OK); + var headers = ResponseHeaders.FromHttpResponseMessage(response); + + // Act + var success = headers.TryGetValues("X-NonExistent", out var values); + + // Assert + Assert.That(success, Is.False); + Assert.That(values, Is.Null); + } + + [Test] + public async global::System.Threading.Tasks.Task WithRawResponseTask_ImplicitConversion_ToTask() + { + // Arrange + var expectedData = "test-data"; + var task = CreateWithRawResponseTask(expectedData, HttpStatusCode.OK); + + // Act - implicitly convert to Task + global::System.Threading.Tasks.Task regularTask = task; + var result = await regularTask; + + // Assert + Assert.That(result, Is.EqualTo(expectedData)); + } + + [Test] + public void WithRawResponseTask_ImplicitConversion_AssignToTaskVariable() + { + // Arrange + var expectedData = "test-data"; + var wrappedTask = CreateWithRawResponseTask(expectedData, HttpStatusCode.OK); + + // Act - assign to Task variable + global::System.Threading.Tasks.Task regularTask = wrappedTask; + + // Assert + Assert.That(regularTask, Is.Not.Null); + Assert.That(regularTask, Is.InstanceOf>()); + } + + // Helper methods + + private static WithRawResponseTask CreateWithRawResponseTask( + T data, + HttpStatusCode statusCode, + Uri? url = null + ) + { + url ??= new Uri("https://api.example.com/test"); + using var httpResponse = CreateHttpResponse(statusCode); + httpResponse.RequestMessage = new HttpRequestMessage(HttpMethod.Get, url); + + var rawResponse = new RawResponse + { + StatusCode = statusCode, + Url = url, + Headers = ResponseHeaders.FromHttpResponseMessage(httpResponse), + }; + + var withRawResponse = new WithRawResponse { Data = data, RawResponse = rawResponse }; + + var task = global::System.Threading.Tasks.Task.FromResult(withRawResponse); + return new WithRawResponseTask(task); + } + + private static HttpResponseMessage CreateHttpResponse(HttpStatusCode statusCode) + { + return new HttpResponseMessage(statusCode) { Content = new StringContent("") }; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.Custom.props b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.Custom.props new file mode 100644 index 000000000000..aac9b5020d80 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.Custom.props @@ -0,0 +1,6 @@ + + diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj new file mode 100644 index 000000000000..ab37b399beed --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/SeedCsharpXmlEntities.Test.csproj @@ -0,0 +1,39 @@ + + + net9.0 + 12 + enable + enable + false + true + true + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/TestClient.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/TestClient.cs new file mode 100644 index 000000000000..f71a20870021 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/TestClient.cs @@ -0,0 +1,6 @@ +using NUnit.Framework; + +namespace SeedCsharpXmlEntities.Test; + +[TestFixture] +public class TestClient; diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Unit/MockServer/BaseMockServerTest.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Unit/MockServer/BaseMockServerTest.cs new file mode 100644 index 000000000000..91d45fe5f270 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Unit/MockServer/BaseMockServerTest.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities; +using WireMock.Logging; +using WireMock.Server; +using WireMock.Settings; + +namespace SeedCsharpXmlEntities.Test.Unit.MockServer; + +public class BaseMockServerTest +{ + protected WireMockServer Server { get; set; } = null!; + + protected SeedCsharpXmlEntitiesClient Client { get; set; } = null!; + + protected RequestOptions RequestOptions { get; set; } = new(); + + [OneTimeSetUp] + public void GlobalSetup() + { + // Start the WireMock server + Server = WireMockServer.Start( + new WireMockServerSettings { Logger = new WireMockConsoleLogger() } + ); + + // Initialize the Client + Client = new SeedCsharpXmlEntitiesClient( + clientOptions: new ClientOptions { BaseUrl = Server.Urls[0], MaxRetries = 0 } + ); + } + + [OneTimeTearDown] + public void GlobalTeardown() + { + Server.Stop(); + Server.Dispose(); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Unit/MockServer/GetTimeZoneTest.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Unit/MockServer/GetTimeZoneTest.cs new file mode 100644 index 000000000000..c960b7457afa --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Unit/MockServer/GetTimeZoneTest.cs @@ -0,0 +1,36 @@ +using NUnit.Framework; +using SeedCsharpXmlEntities.Test.Utils; + +namespace SeedCsharpXmlEntities.Test.Unit.MockServer; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class GetTimeZoneTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public async Task MockServerTest() + { + const string mockResponse = """ + { + "timeZoneOffset": "timeZoneOffset", + "mathExpression": "mathExpression", + "validEntity": "validEntity", + "specialChars": "specialChars", + "documentationLink": "documentationLink", + "escapedDocumentationLink": "escapedDocumentationLink" + } + """; + + Server + .Given(WireMock.RequestBuilders.Request.Create().WithPath("/timezone").UsingGet()) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.GetTimeZoneAsync(); + JsonAssert.AreEqual(response, mockResponse); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/AdditionalPropertiesComparer.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/AdditionalPropertiesComparer.cs new file mode 100644 index 000000000000..f4dffe0f9468 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/AdditionalPropertiesComparer.cs @@ -0,0 +1,219 @@ +using global::System.Text.Json; +using NUnit.Framework.Constraints; +using SeedCsharpXmlEntities; +using SeedCsharpXmlEntities.Core; + +namespace NUnit.Framework; + +/// +/// Extensions for EqualConstraint to handle AdditionalProperties values. +/// +public static class AdditionalPropertiesComparerExtensions +{ + /// + /// Modifies the EqualConstraint to handle AdditionalProperties instances by comparing their + /// serialized JSON representations. This handles the type mismatch between native C# types + /// and JsonElement values that occur when comparing manually constructed objects with + /// deserialized objects. + /// + /// The EqualConstraint to modify. + /// The same constraint instance for method chaining. + public static EqualConstraint UsingAdditionalPropertiesComparer(this EqualConstraint constraint) + { + constraint.Using( + (x, y) => + { + if (x.Count != y.Count) + { + return false; + } + + foreach (var key in x.Keys) + { + if (!y.ContainsKey(key)) + { + return false; + } + + var xElement = JsonUtils.SerializeToElement(x[key]); + var yElement = JsonUtils.SerializeToElement(y[key]); + + if (!JsonElementsAreEqual(xElement, yElement)) + { + return false; + } + } + + return true; + } + ); + + return constraint; + } + + /// + /// Modifies the EqualConstraint to handle Dictionary<string, object?> values by comparing + /// their serialized JSON representations. This handles the type mismatch between native C# types + /// and JsonElement values that occur when comparing manually constructed objects with + /// deserialized objects. + /// + /// The EqualConstraint to modify. + /// The same constraint instance for method chaining. + public static EqualConstraint UsingObjectDictionaryComparer(this EqualConstraint constraint) + { + constraint.Using>( + (x, y) => + { + if (x.Count != y.Count) + { + return false; + } + + foreach (var key in x.Keys) + { + if (!y.ContainsKey(key)) + { + return false; + } + + var xElement = JsonUtils.SerializeToElement(x[key]); + var yElement = JsonUtils.SerializeToElement(y[key]); + + if (!JsonElementsAreEqual(xElement, yElement)) + { + return false; + } + } + + return true; + } + ); + + return constraint; + } + + internal static bool JsonElementsAreEqualPublic(JsonElement x, JsonElement y) => + JsonElementsAreEqual(x, y); + + private static bool JsonElementsAreEqual(JsonElement x, JsonElement y) + { + if (x.ValueKind != y.ValueKind) + { + return false; + } + + return x.ValueKind switch + { + JsonValueKind.Object => CompareJsonObjects(x, y), + JsonValueKind.Array => CompareJsonArrays(x, y), + JsonValueKind.String => x.GetString() == y.GetString(), + JsonValueKind.Number => x.GetDecimal() == y.GetDecimal(), + JsonValueKind.True => true, + JsonValueKind.False => true, + JsonValueKind.Null => true, + _ => false, + }; + } + + private static bool CompareJsonObjects(JsonElement x, JsonElement y) + { + var xProps = new Dictionary(); + var yProps = new Dictionary(); + + foreach (var prop in x.EnumerateObject()) + xProps[prop.Name] = prop.Value; + + foreach (var prop in y.EnumerateObject()) + yProps[prop.Name] = prop.Value; + + if (xProps.Count != yProps.Count) + { + return false; + } + + foreach (var key in xProps.Keys) + { + if (!yProps.ContainsKey(key)) + { + return false; + } + + if (!JsonElementsAreEqual(xProps[key], yProps[key])) + { + return false; + } + } + + return true; + } + + private static bool CompareJsonArrays(JsonElement x, JsonElement y) + { + var xArray = x.EnumerateArray().ToList(); + var yArray = y.EnumerateArray().ToList(); + + if (xArray.Count != yArray.Count) + { + return false; + } + + for (var i = 0; i < xArray.Count; i++) + { + if (!JsonElementsAreEqual(xArray[i], yArray[i])) + { + return false; + } + } + + return true; + } + + /// + /// Modifies the EqualConstraint to handle cross-type comparisons involving JsonElement. + /// When UsingPropertiesComparer() walks object properties and encounters a property typed as + /// 'object', the expected side may be a Dictionary<object, object?> while the actual + /// (deserialized) side is a JsonElement. These typed predicates bridge that gap by serializing + /// the non-JsonElement side and comparing JSON representations. + /// + /// Uses typed Func<TExpected, TActual, bool> predicates instead of a non-generic + /// IComparer/IEqualityComparer so that NUnit's CanCompare type check ensures these only + /// fire when one side is a JsonElement, letting UsingPropertiesComparer() handle all + /// same-type comparisons normally. + /// + /// The EqualConstraint to modify. + /// The same constraint instance for method chaining. + public static EqualConstraint UsingJsonSerializationComparer(this EqualConstraint constraint) + { + // Handle: expected is non-JsonElement, actual is JsonElement + constraint.Using( + (actualJsonElement, expectedObj) => + { + try + { + var expectedElement = JsonUtils.SerializeToElement(expectedObj); + return JsonElementsAreEqualPublic(expectedElement, actualJsonElement); + } + catch + { + return false; + } + } + ); + // Handle reverse: expected is JsonElement, actual is non-JsonElement + constraint.Using( + (actualObj, expectedJsonElement) => + { + try + { + var actualElement = JsonUtils.SerializeToElement(actualObj); + return JsonElementsAreEqualPublic(expectedJsonElement, actualElement); + } + catch + { + return false; + } + } + ); + return constraint; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/JsonAssert.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/JsonAssert.cs new file mode 100644 index 000000000000..940853a68878 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/JsonAssert.cs @@ -0,0 +1,33 @@ +using global::System.Text.Json; +using NUnit.Framework; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities.Test.Utils; + +internal static class JsonAssert +{ + /// + /// Asserts that the serialized JSON of an object equals the expected JSON string. + /// Uses JsonElement comparison for reliable deep equality of collections and union types. + /// + internal static void AreEqual(object actual, string expectedJson) + { + var actualElement = JsonUtils.SerializeToElement(actual); + var expectedElement = JsonUtils.Deserialize(expectedJson); + Assert.That(actualElement, Is.EqualTo(expectedElement).UsingJsonElementComparer()); + } + + /// + /// Asserts that the given JSON string survives a deserialization/serialization round-trip. + /// Deserializes to T, re-serializes to get the canonical form, then verifies a second + /// round-trip produces the same canonical form (idempotency). This accounts for serializer + /// options like WhenWritingNull that may normalize the output. + /// + internal static void Roundtrips(string json) + { + var deserialized = JsonUtils.Deserialize(json); + var serialized = JsonUtils.Serialize(deserialized!); + var deserialized2 = JsonUtils.Deserialize(serialized); + AreEqual(deserialized2!, serialized); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/JsonElementComparer.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/JsonElementComparer.cs new file mode 100644 index 000000000000..36fa0e9d4ed1 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/JsonElementComparer.cs @@ -0,0 +1,243 @@ +using global::System.Text.Json; +using NUnit.Framework.Constraints; + +namespace NUnit.Framework; + +/// +/// Extensions for EqualConstraint to handle JsonElement objects. +/// +public static class JsonElementComparerExtensions +{ + /// + /// Extension method for comparing JsonElement objects in NUnit tests. + /// Property order doesn't matter, but array order does matter. + /// Includes special handling for DateTime string formats. + /// + /// The Is.EqualTo() constraint instance. + /// A constraint that can compare JsonElements with detailed diffs. + public static EqualConstraint UsingJsonElementComparer(this EqualConstraint constraint) + { + return constraint.Using(new JsonElementComparer()); + } +} + +/// +/// Equality comparer for JsonElement with detailed reporting. +/// Property order doesn't matter, but array order does matter. +/// Now includes special handling for DateTime string formats with improved null handling. +/// +public class JsonElementComparer : IEqualityComparer +{ + private string _failurePath = string.Empty; + + /// + public bool Equals(JsonElement x, JsonElement y) + { + _failurePath = string.Empty; + return CompareJsonElements(x, y, string.Empty); + } + + /// + public int GetHashCode(JsonElement obj) + { + return JsonSerializer.Serialize(obj).GetHashCode(); + } + + private bool CompareJsonElements(JsonElement x, JsonElement y, string path) + { + // If value kinds don't match, they're not equivalent + if (x.ValueKind != y.ValueKind) + { + _failurePath = $"{path}: Expected {x.ValueKind} but got {y.ValueKind}"; + return false; + } + + switch (x.ValueKind) + { + case JsonValueKind.Object: + return CompareJsonObjects(x, y, path); + + case JsonValueKind.Array: + return CompareJsonArraysInOrder(x, y, path); + + case JsonValueKind.String: + string? xStr = x.GetString(); + string? yStr = y.GetString(); + + // Handle null strings + if (xStr is null && yStr is null) + return true; + + if (xStr is null || yStr is null) + { + _failurePath = + $"{path}: Expected {(xStr is null ? "null" : $"\"{xStr}\"")} but got {(yStr is null ? "null" : $"\"{yStr}\"")}"; + return false; + } + + // Check if they are identical strings + if (xStr == yStr) + return true; + + // Try to handle DateTime strings + if (IsLikelyDateTimeString(xStr) && IsLikelyDateTimeString(yStr)) + { + if (AreEquivalentDateTimeStrings(xStr, yStr)) + return true; + } + + _failurePath = $"{path}: Expected \"{xStr}\" but got \"{yStr}\""; + return false; + + case JsonValueKind.Number: + if (x.GetDecimal() != y.GetDecimal()) + { + if (x.GetDouble() != y.GetDouble()) + { + if (x.GetSingle() != y.GetSingle()) + { + _failurePath = + $"{path}: Expected {x.GetDecimal()} but got {y.GetDecimal()}"; + return false; + } + } + } + + return true; + + case JsonValueKind.True: + case JsonValueKind.False: + if (x.GetBoolean() != y.GetBoolean()) + { + _failurePath = $"{path}: Expected {x.GetBoolean()} but got {y.GetBoolean()}"; + return false; + } + + return true; + + case JsonValueKind.Null: + return true; + + default: + _failurePath = $"{path}: Unsupported JsonValueKind {x.ValueKind}"; + return false; + } + } + + private bool IsLikelyDateTimeString(string? str) + { + // Simple heuristic to identify likely ISO date time strings + return str is not null + && (str.Contains("T") && (str.EndsWith("Z") || str.Contains("+") || str.Contains("-"))); + } + + private bool AreEquivalentDateTimeStrings(string str1, string str2) + { + // Try to parse both as DateTime + if (DateTime.TryParse(str1, out DateTime dt1) && DateTime.TryParse(str2, out DateTime dt2)) + { + return dt1 == dt2; + } + + return false; + } + + private bool CompareJsonObjects(JsonElement x, JsonElement y, string path) + { + // Create dictionaries for both JSON objects + var xProps = new Dictionary(); + var yProps = new Dictionary(); + + foreach (var prop in x.EnumerateObject()) + xProps[prop.Name] = prop.Value; + + foreach (var prop in y.EnumerateObject()) + yProps[prop.Name] = prop.Value; + + // Check if all properties in x exist in y + foreach (var key in xProps.Keys) + { + if (!yProps.ContainsKey(key)) + { + _failurePath = $"{path}: Missing property '{key}'"; + return false; + } + } + + // Check if y has extra properties + foreach (var key in yProps.Keys) + { + if (!xProps.ContainsKey(key)) + { + _failurePath = $"{path}: Unexpected property '{key}'"; + return false; + } + } + + // Compare each property value + foreach (var key in xProps.Keys) + { + var propPath = string.IsNullOrEmpty(path) ? key : $"{path}.{key}"; + if (!CompareJsonElements(xProps[key], yProps[key], propPath)) + { + return false; + } + } + + return true; + } + + private bool CompareJsonArraysInOrder(JsonElement x, JsonElement y, string path) + { + var xArray = x.EnumerateArray(); + var yArray = y.EnumerateArray(); + + // Count x elements + var xCount = 0; + var xElements = new List(); + foreach (var item in xArray) + { + xElements.Add(item); + xCount++; + } + + // Count y elements + var yCount = 0; + var yElements = new List(); + foreach (var item in yArray) + { + yElements.Add(item); + yCount++; + } + + // Check if counts match + if (xCount != yCount) + { + _failurePath = $"{path}: Expected {xCount} items but found {yCount}"; + return false; + } + + // Compare elements in order + for (var i = 0; i < xCount; i++) + { + var itemPath = $"{path}[{i}]"; + if (!CompareJsonElements(xElements[i], yElements[i], itemPath)) + { + return false; + } + } + + return true; + } + + /// + public override string ToString() + { + if (!string.IsNullOrEmpty(_failurePath)) + { + return $"JSON comparison failed at {_failurePath}"; + } + + return "JsonElementEqualityComparer"; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/NUnitExtensions.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/NUnitExtensions.cs new file mode 100644 index 000000000000..816f4c010e6e --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/NUnitExtensions.cs @@ -0,0 +1,32 @@ +using NUnit.Framework.Constraints; + +namespace NUnit.Framework; + +/// +/// Extensions for NUnit constraints. +/// +public static class NUnitExtensions +{ + /// + /// Modifies the EqualConstraint to use our own set of default comparers. + /// + /// + /// + public static EqualConstraint UsingDefaults(this EqualConstraint constraint) => + constraint + .UsingPropertiesComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingReadOnlyMemoryComparer() + .UsingOneOfComparer() + .UsingJsonElementComparer() + .UsingOptionalComparer() + .UsingObjectDictionaryComparer() + .UsingAdditionalPropertiesComparer() + .UsingJsonSerializationComparer(); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/OneOfComparer.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/OneOfComparer.cs new file mode 100644 index 000000000000..5284755b7e9a --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/OneOfComparer.cs @@ -0,0 +1,100 @@ +using NUnit.Framework.Constraints; +using OneOf; +using SeedCsharpXmlEntities.Core; + +namespace NUnit.Framework; + +/// +/// Extensions for EqualConstraint to handle OneOf values. +/// +public static class EqualConstraintExtensions +{ + /// + /// Modifies the EqualConstraint to handle OneOf instances by comparing their inner values. + /// This works alongside other comparison modifiers like UsingPropertiesComparer. + /// + /// The EqualConstraint to modify. + /// The same constraint instance for method chaining. + public static EqualConstraint UsingOneOfComparer(this EqualConstraint constraint) + { + // Register a comparer factory for IOneOf types + constraint.Using( + (x, y) => + { + // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (x.Value is null && y.Value is null) + { + return true; + } + + if (x.Value is null) + { + return false; + } + + // Undiscriminated unions of string enums are only distinguishable by their + // wire value: the concrete member type is not recoverable when deserializing, + // so two members with the same string value are considered equal. + if (x.Value is IStringEnum xStringEnum && y.Value is IStringEnum yStringEnum) + { + return xStringEnum.Value == yStringEnum.Value; + } + + var propertiesComparer = new NUnitEqualityComparer(); + var tolerance = Tolerance.Default; + propertiesComparer.CompareProperties = true; + // Add OneOf comparer to handle nested OneOf values (e.g., in Lists) + propertiesComparer.ExternalComparers.Add( + new OneOfEqualityAdapter(propertiesComparer) + ); + return propertiesComparer.AreEqual(x.Value, y.Value, ref tolerance); + } + ); + + return constraint; + } + + /// + /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. + /// This enables recursive comparison of nested OneOf values. + /// + private class OneOfEqualityAdapter : EqualityAdapter + { + private readonly NUnitEqualityComparer _comparer; + + public OneOfEqualityAdapter(NUnitEqualityComparer comparer) + { + _comparer = comparer; + } + + public override bool CanCompare(object? x, object? y) + { + return x is IOneOf && y is IOneOf; + } + + public override bool AreEqual(object? x, object? y) + { + var oneOfX = (IOneOf?)x; + var oneOfY = (IOneOf?)y; + + // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (oneOfX?.Value is null && oneOfY?.Value is null) + { + return true; + } + + if (oneOfX?.Value is null || oneOfY?.Value is null) + { + return false; + } + + if (oneOfX.Value is IStringEnum xStringEnum && oneOfY.Value is IStringEnum yStringEnum) + { + return xStringEnum.Value == yStringEnum.Value; + } + + var tolerance = Tolerance.Default; + return _comparer.AreEqual(oneOfX.Value, oneOfY.Value, ref tolerance); + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/OptionalComparer.cs new file mode 100644 index 000000000000..3cd4bd8ae2f8 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/OptionalComparer.cs @@ -0,0 +1,104 @@ +using NUnit.Framework.Constraints; +using OneOf; +using SeedCsharpXmlEntities.Core; + +namespace NUnit.Framework; + +/// +/// Extensions for EqualConstraint to handle Optional values. +/// +public static class OptionalComparerExtensions +{ + /// + /// Modifies the EqualConstraint to handle Optional instances by comparing their IsDefined state and inner values. + /// This works alongside other comparison modifiers like UsingPropertiesComparer. + /// + /// The EqualConstraint to modify. + /// The same constraint instance for method chaining. + public static EqualConstraint UsingOptionalComparer(this EqualConstraint constraint) + { + // Register a comparer factory for IOptional types + constraint.Using( + (x, y) => + { + // Both must have the same IsDefined state + if (x.IsDefined != y.IsDefined) + { + return false; + } + + // If both are undefined, they're equal + if (!x.IsDefined) + { + return true; + } + + // Both are defined, compare their boxed values + var xValue = x.GetBoxedValue(); + var yValue = y.GetBoxedValue(); + + // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (xValue is null && yValue is null) + { + return true; + } + + if (xValue is null || yValue is null) + { + return false; + } + + // Use NUnit's property comparer for the inner values + var propertiesComparer = new NUnitEqualityComparer(); + var tolerance = Tolerance.Default; + propertiesComparer.CompareProperties = true; + // Add OneOf comparer to handle nested OneOf values (e.g., in Lists within Optional) + propertiesComparer.ExternalComparers.Add( + new OneOfEqualityAdapter(propertiesComparer) + ); + return propertiesComparer.AreEqual(xValue, yValue, ref tolerance); + } + ); + + return constraint; + } + + /// + /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. + /// + private class OneOfEqualityAdapter : EqualityAdapter + { + private readonly NUnitEqualityComparer _comparer; + + public OneOfEqualityAdapter(NUnitEqualityComparer comparer) + { + _comparer = comparer; + } + + public override bool CanCompare(object? x, object? y) + { + return x is IOneOf && y is IOneOf; + } + + public override bool AreEqual(object? x, object? y) + { + var oneOfX = (IOneOf?)x; + var oneOfY = (IOneOf?)y; + + // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (oneOfX?.Value is null && oneOfY?.Value is null) + { + return true; + } + + if (oneOfX?.Value is null || oneOfY?.Value is null) + { + return false; + } + + var tolerance = Tolerance.Default; + return _comparer.AreEqual(oneOfX.Value, oneOfY.Value, ref tolerance); + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/ReadOnlyMemoryComparer.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/ReadOnlyMemoryComparer.cs new file mode 100644 index 000000000000..fc0b595a5e54 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities.Test/Utils/ReadOnlyMemoryComparer.cs @@ -0,0 +1,87 @@ +using NUnit.Framework.Constraints; + +namespace NUnit.Framework; + +/// +/// Extensions for NUnit constraints. +/// +public static class ReadOnlyMemoryComparerExtensions +{ + /// + /// Extension method for comparing ReadOnlyMemory<T> in NUnit tests. + /// + /// The type of elements in the ReadOnlyMemory. + /// The Is.EqualTo() constraint instance. + /// A constraint that can compare ReadOnlyMemory<T>. + public static EqualConstraint UsingReadOnlyMemoryComparer(this EqualConstraint constraint) + where T : IComparable + { + return constraint.Using(new ReadOnlyMemoryComparer()); + } +} + +/// +/// Comparer for ReadOnlyMemory<T>. Compares sequences by value. +/// +/// +/// The type of elements in the ReadOnlyMemory. +/// +public class ReadOnlyMemoryComparer : IComparer> + where T : IComparable +{ + /// + public int Compare(ReadOnlyMemory x, ReadOnlyMemory y) + { + // Check if sequences are equal + var xSpan = x.Span; + var ySpan = y.Span; + + // Optimized case for IEquatable implementations + if (typeof(IEquatable).IsAssignableFrom(typeof(T))) + { + var areEqual = xSpan.SequenceEqual(ySpan); + if (areEqual) + { + return 0; // Sequences are equal + } + } + else + { + // Manual equality check for non-IEquatable types + if (xSpan.Length == ySpan.Length) + { + var areEqual = true; + for (var i = 0; i < xSpan.Length; i++) + { + if (!EqualityComparer.Default.Equals(xSpan[i], ySpan[i])) + { + areEqual = false; + break; + } + } + + if (areEqual) + { + return 0; // Sequences are equal + } + } + } + + // For non-equal sequences, we need to return a consistent ordering + // First compare lengths + if (x.Length != y.Length) + return x.Length.CompareTo(y.Length); + + // Same length but different content - compare first differing element + for (var i = 0; i < x.Length; i++) + { + if (!EqualityComparer.Default.Equals(xSpan[i], ySpan[i])) + { + return xSpan[i].CompareTo(ySpan[i]); + } + } + + // Should never reach here if not equal + return 0; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/ApiResponse.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/ApiResponse.cs new file mode 100644 index 000000000000..cd8bc2ebe8b6 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/ApiResponse.cs @@ -0,0 +1,13 @@ +using global::System.Net.Http; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// The response object returned from the API. +/// +internal record ApiResponse +{ + internal required int StatusCode { get; init; } + + internal required HttpResponseMessage Raw { get; init; } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/BaseRequest.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/BaseRequest.cs new file mode 100644 index 000000000000..caf83514a692 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/BaseRequest.cs @@ -0,0 +1,67 @@ +using global::System.Net.Http; +using global::System.Net.Http.Headers; +using global::System.Text; + +namespace SeedCsharpXmlEntities.Core; + +internal abstract record BaseRequest +{ + internal string? BaseUrl { get; init; } + + internal required HttpMethod Method { get; init; } + + internal required string Path { get; init; } + + internal string? ContentType { get; init; } + + /// + /// The query string for this request (including the leading '?' if non-empty). + /// + internal string? QueryString { get; init; } + + internal Dictionary Headers { get; init; } = + new(StringComparer.OrdinalIgnoreCase); + + internal IRequestOptions? Options { get; init; } + + internal abstract HttpContent? CreateContent(); + + protected static ( + Encoding encoding, + string? charset, + string mediaType + ) ParseContentTypeOrDefault( + string? contentType, + Encoding encodingFallback, + string mediaTypeFallback + ) + { + var encoding = encodingFallback; + var mediaType = mediaTypeFallback; + string? charset = null; + if (string.IsNullOrEmpty(contentType)) + { + return (encoding, charset, mediaType); + } + + if (!MediaTypeHeaderValue.TryParse(contentType, out var mediaTypeHeaderValue)) + { + return (encoding, charset, mediaType); + } + + if (!string.IsNullOrEmpty(mediaTypeHeaderValue.CharSet)) + { + charset = mediaTypeHeaderValue.CharSet; + encoding = Encoding.GetEncoding(mediaTypeHeaderValue.CharSet); + } + + if (!string.IsNullOrEmpty(mediaTypeHeaderValue.MediaType)) + { + mediaType = mediaTypeHeaderValue.MediaType; + } + + return (encoding, charset, mediaType); + } + + protected static Encoding Utf8NoBom => EncodingCache.Utf8NoBom; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/CollectionItemSerializer.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/CollectionItemSerializer.cs new file mode 100644 index 000000000000..ef7d24e58d75 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/CollectionItemSerializer.cs @@ -0,0 +1,91 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Json collection converter. +/// +/// Type of item to convert. +/// Converter to use for individual items. +internal class CollectionItemSerializer + : JsonConverter> + where TConverterType : JsonConverter, new() +{ + private static readonly TConverterType _converter = new TConverterType(); + + /// + /// Reads a json string and deserializes it into an object. + /// + /// Json reader. + /// Type to convert. + /// Serializer options. + /// Created object. + public override IEnumerable? Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType == JsonTokenType.Null) + { + return default; + } + + var jsonSerializerOptions = new JsonSerializerOptions(options); + jsonSerializerOptions.Converters.Clear(); + jsonSerializerOptions.Converters.Add(_converter); + + var returnValue = new List(); + + while (reader.TokenType != JsonTokenType.EndArray) + { + if (reader.TokenType != JsonTokenType.StartArray) + { + var item = (TDatatype)( + JsonSerializer.Deserialize(ref reader, typeof(TDatatype), jsonSerializerOptions) + ?? throw new global::System.Exception( + $"Failed to deserialize collection item of type {typeof(TDatatype)}" + ) + ); + returnValue.Add(item); + } + + reader.Read(); + } + + return returnValue; + } + + /// + /// Writes a json string. + /// + /// Json writer. + /// Value to write. + /// Serializer options. + public override void Write( + Utf8JsonWriter writer, + IEnumerable? value, + JsonSerializerOptions options + ) + { + if (value is null) + { + writer.WriteNullValue(); + return; + } + + var jsonSerializerOptions = new JsonSerializerOptions(options); + jsonSerializerOptions.Converters.Clear(); + jsonSerializerOptions.Converters.Add(_converter); + + writer.WriteStartArray(); + + foreach (var data in value) + { + JsonSerializer.Serialize(writer, data, jsonSerializerOptions); + } + + writer.WriteEndArray(); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Constants.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Constants.cs new file mode 100644 index 000000000000..79ccd1bff388 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Constants.cs @@ -0,0 +1,7 @@ +namespace SeedCsharpXmlEntities.Core; + +internal static class Constants +{ + public const string DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffK"; + public const string DateFormat = "yyyy-MM-dd"; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/DateOnlyConverter.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/DateOnlyConverter.cs new file mode 100644 index 000000000000..2a52421a4a45 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/DateOnlyConverter.cs @@ -0,0 +1,747 @@ +// ReSharper disable All +#pragma warning disable + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using global::System.Diagnostics; +using global::System.Diagnostics.CodeAnalysis; +using global::System.Globalization; +using global::System.Runtime.CompilerServices; +using global::System.Runtime.InteropServices; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +// ReSharper disable SuggestVarOrType_SimpleTypes +// ReSharper disable SuggestVarOrType_BuiltInTypes + +namespace SeedCsharpXmlEntities.Core +{ + /// + /// Custom converter for handling the data type with the System.Text.Json library. + /// + /// + /// This class backported from: + /// + /// System.Text.Json.Serialization.Converters.DateOnlyConverter + /// + public sealed class DateOnlyConverter : JsonConverter + { + private const int FormatLength = 10; // YYYY-MM-DD + + private const int MaxEscapedFormatLength = + FormatLength * JsonConstants.MaxExpansionFactorWhileEscaping; + + /// + public override DateOnly Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType != JsonTokenType.String) + { + ThrowHelper.ThrowInvalidOperationException_ExpectedString(reader.TokenType); + } + + return ReadCore(ref reader); + } + + /// + public override DateOnly ReadAsPropertyName( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); + return ReadCore(ref reader); + } + + private static DateOnly ReadCore(ref Utf8JsonReader reader) + { + if ( + !JsonHelpers.IsInRangeInclusive( + reader.ValueLength(), + FormatLength, + MaxEscapedFormatLength + ) + ) + { + ThrowHelper.ThrowFormatException(DataType.DateOnly); + } + + scoped ReadOnlySpan source; + if (!reader.HasValueSequence && !reader.ValueIsEscaped) + { + source = reader.ValueSpan; + } + else + { + Span stackSpan = stackalloc byte[MaxEscapedFormatLength]; + int bytesWritten = reader.CopyString(stackSpan); + source = stackSpan.Slice(0, bytesWritten); + } + + if (!JsonHelpers.TryParseAsIso(source, out DateOnly value)) + { + ThrowHelper.ThrowFormatException(DataType.DateOnly); + } + + return value; + } + + /// + public override void Write( + Utf8JsonWriter writer, + DateOnly value, + JsonSerializerOptions options + ) + { +#if NET8_0_OR_GREATER + Span buffer = stackalloc byte[FormatLength]; +#else + Span buffer = stackalloc char[FormatLength]; +#endif + // ReSharper disable once RedundantAssignment + bool formattedSuccessfully = value.TryFormat( + buffer, + out int charsWritten, + "O".AsSpan(), + CultureInfo.InvariantCulture + ); + Debug.Assert(formattedSuccessfully && charsWritten == FormatLength); + writer.WriteStringValue(buffer); + } + + /// + public override void WriteAsPropertyName( + Utf8JsonWriter writer, + DateOnly value, + JsonSerializerOptions options + ) + { +#if NET8_0_OR_GREATER + Span buffer = stackalloc byte[FormatLength]; +#else + Span buffer = stackalloc char[FormatLength]; +#endif + // ReSharper disable once RedundantAssignment + bool formattedSuccessfully = value.TryFormat( + buffer, + out int charsWritten, + "O".AsSpan(), + CultureInfo.InvariantCulture + ); + Debug.Assert(formattedSuccessfully && charsWritten == FormatLength); + writer.WritePropertyName(buffer); + } + } + + internal static class JsonConstants + { + // The maximum number of fraction digits the Json DateTime parser allows + public const int DateTimeParseNumFractionDigits = 16; + + // In the worst case, an ASCII character represented as a single utf-8 byte could expand 6x when escaped. + public const int MaxExpansionFactorWhileEscaping = 6; + + // The largest fraction expressible by TimeSpan and DateTime formats + public const int MaxDateTimeFraction = 9_999_999; + + // TimeSpan and DateTime formats allow exactly up to many digits for specifying the fraction after the seconds. + public const int DateTimeNumFractionDigits = 7; + + public const byte UtcOffsetToken = (byte)'Z'; + + public const byte TimePrefix = (byte)'T'; + + public const byte Period = (byte)'.'; + + public const byte Hyphen = (byte)'-'; + + public const byte Colon = (byte)':'; + + public const byte Plus = (byte)'+'; + } + + // ReSharper disable SuggestVarOrType_Elsewhere + // ReSharper disable SuggestVarOrType_SimpleTypes + // ReSharper disable SuggestVarOrType_BuiltInTypes + + internal static class JsonHelpers + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsInRangeInclusive(int value, int lowerBound, int upperBound) => + (uint)(value - lowerBound) <= (uint)(upperBound - lowerBound); + + public static bool IsDigit(byte value) => (uint)(value - '0') <= '9' - '0'; + + [StructLayout(LayoutKind.Auto)] + private struct DateTimeParseData + { + public int Year; + public int Month; + public int Day; + public bool IsCalendarDateOnly; + public int Hour; + public int Minute; + public int Second; + public int Fraction; // This value should never be greater than 9_999_999. + public int OffsetHours; + public int OffsetMinutes; + + // ReSharper disable once NotAccessedField.Local + public byte OffsetToken; + } + + public static bool TryParseAsIso(ReadOnlySpan source, out DateOnly value) + { + if ( + TryParseDateTimeOffset(source, out DateTimeParseData parseData) + && parseData.IsCalendarDateOnly + && TryCreateDateTime(parseData, DateTimeKind.Unspecified, out DateTime dateTime) + ) + { + value = DateOnly.FromDateTime(dateTime); + return true; + } + + value = default; + return false; + } + + /// + /// ISO 8601 date time parser (ISO 8601-1:2019). + /// + /// The date/time to parse in UTF-8 format. + /// The parsed for the given . + /// + /// Supports extended calendar date (5.2.2.1) and complete (5.4.2.1) calendar date/time of day + /// representations with optional specification of seconds and fractional seconds. + /// + /// Times can be explicitly specified as UTC ("Z" - 5.3.3) or offsets from UTC ("+/-hh:mm" 5.3.4.2). + /// If unspecified they are considered to be local per spec. + /// + /// Examples: (TZD is either "Z" or hh:mm offset from UTC) + /// + /// YYYY-MM-DD (e.g. 1997-07-16) + /// YYYY-MM-DDThh:mm (e.g. 1997-07-16T19:20) + /// YYYY-MM-DDThh:mm:ss (e.g. 1997-07-16T19:20:30) + /// YYYY-MM-DDThh:mm:ss.s (e.g. 1997-07-16T19:20:30.45) + /// YYYY-MM-DDThh:mmTZD (e.g. 1997-07-16T19:20+01:00) + /// YYYY-MM-DDThh:mm:ssTZD (e.g. 1997-07-16T19:20:3001:00) + /// YYYY-MM-DDThh:mm:ss.sTZD (e.g. 1997-07-16T19:20:30.45Z) + /// + /// Generally speaking we always require the "extended" option when one exists (3.1.3.5). + /// The extended variants have separator characters between components ('-', ':', '.', etc.). + /// Spaces are not permitted. + /// + /// "true" if successfully parsed. + private static bool TryParseDateTimeOffset( + ReadOnlySpan source, + out DateTimeParseData parseData + ) + { + parseData = default; + + // too short datetime + Debug.Assert(source.Length >= 10); + + // Parse the calendar date + // ----------------------- + // ISO 8601-1:2019 5.2.2.1b "Calendar date complete extended format" + // [dateX] = [year]["-"][month]["-"][day] + // [year] = [YYYY] [0000 - 9999] (4.3.2) + // [month] = [MM] [01 - 12] (4.3.3) + // [day] = [DD] [01 - 28, 29, 30, 31] (4.3.4) + // + // Note: 5.2.2.2 "Representations with reduced precision" allows for + // just [year]["-"][month] (a) and just [year] (b), but we currently + // don't permit it. + + { + uint digit1 = source[0] - (uint)'0'; + uint digit2 = source[1] - (uint)'0'; + uint digit3 = source[2] - (uint)'0'; + uint digit4 = source[3] - (uint)'0'; + + if (digit1 > 9 || digit2 > 9 || digit3 > 9 || digit4 > 9) + { + return false; + } + + parseData.Year = (int)(digit1 * 1000 + digit2 * 100 + digit3 * 10 + digit4); + } + + if ( + source[4] != JsonConstants.Hyphen + || !TryGetNextTwoDigits(source.Slice(start: 5, length: 2), ref parseData.Month) + || source[7] != JsonConstants.Hyphen + || !TryGetNextTwoDigits(source.Slice(start: 8, length: 2), ref parseData.Day) + ) + { + return false; + } + + // We now have YYYY-MM-DD [dateX] + // ReSharper disable once ConvertIfStatementToSwitchStatement + if (source.Length == 10) + { + parseData.IsCalendarDateOnly = true; + return true; + } + + // Parse the time of day + // --------------------- + // + // ISO 8601-1:2019 5.3.1.2b "Local time of day complete extended format" + // [timeX] = ["T"][hour][":"][min][":"][sec] + // [hour] = [hh] [00 - 23] (4.3.8a) + // [minute] = [mm] [00 - 59] (4.3.9a) + // [sec] = [ss] [00 - 59, 60 with a leap second] (4.3.10a) + // + // ISO 8601-1:2019 5.3.3 "UTC of day" + // [timeX]["Z"] + // + // ISO 8601-1:2019 5.3.4.2 "Local time of day with the time shift between + // local timescale and UTC" (Extended format) + // + // [shiftX] = ["+"|"-"][hour][":"][min] + // + // Notes: + // + // "T" is optional per spec, but _only_ when times are used alone. In our + // case, we're reading out a complete date & time and as such require "T". + // (5.4.2.1b). + // + // For [timeX] We allow seconds to be omitted per 5.3.1.3a "Representations + // with reduced precision". 5.3.1.3b allows just specifying the hour, but + // we currently don't permit this. + // + // Decimal fractions are allowed for hours, minutes and seconds (5.3.14). + // We only allow fractions for seconds currently. Lower order components + // can't follow, i.e. you can have T23.3, but not T23.3:04. There must be + // one digit, but the max number of digits is implementation defined. We + // currently allow up to 16 digits of fractional seconds only. While we + // support 16 fractional digits we only parse the first seven, anything + // past that is considered a zero. This is to stay compatible with the + // DateTime implementation which is limited to this resolution. + + if (source.Length < 16) + { + // Source does not have enough characters for YYYY-MM-DDThh:mm + return false; + } + + // Parse THH:MM (e.g. "T10:32") + if ( + source[10] != JsonConstants.TimePrefix + || source[13] != JsonConstants.Colon + || !TryGetNextTwoDigits(source.Slice(start: 11, length: 2), ref parseData.Hour) + || !TryGetNextTwoDigits(source.Slice(start: 14, length: 2), ref parseData.Minute) + ) + { + return false; + } + + // We now have YYYY-MM-DDThh:mm + Debug.Assert(source.Length >= 16); + if (source.Length == 16) + { + return true; + } + + byte curByte = source[16]; + int sourceIndex = 17; + + // Either a TZD ['Z'|'+'|'-'] or a seconds separator [':'] is valid at this point + switch (curByte) + { + case JsonConstants.UtcOffsetToken: + parseData.OffsetToken = JsonConstants.UtcOffsetToken; + return sourceIndex == source.Length; + case JsonConstants.Plus: + case JsonConstants.Hyphen: + parseData.OffsetToken = curByte; + return ParseOffset(ref parseData, source.Slice(sourceIndex)); + case JsonConstants.Colon: + break; + default: + return false; + } + + // Try reading the seconds + if ( + source.Length < 19 + || !TryGetNextTwoDigits(source.Slice(start: 17, length: 2), ref parseData.Second) + ) + { + return false; + } + + // We now have YYYY-MM-DDThh:mm:ss + Debug.Assert(source.Length >= 19); + if (source.Length == 19) + { + return true; + } + + curByte = source[19]; + sourceIndex = 20; + + // Either a TZD ['Z'|'+'|'-'] or a seconds decimal fraction separator ['.'] is valid at this point + switch (curByte) + { + case JsonConstants.UtcOffsetToken: + parseData.OffsetToken = JsonConstants.UtcOffsetToken; + return sourceIndex == source.Length; + case JsonConstants.Plus: + case JsonConstants.Hyphen: + parseData.OffsetToken = curByte; + return ParseOffset(ref parseData, source.Slice(sourceIndex)); + case JsonConstants.Period: + break; + default: + return false; + } + + // Source does not have enough characters for second fractions (i.e. ".s") + // YYYY-MM-DDThh:mm:ss.s + if (source.Length < 21) + { + return false; + } + + // Parse fraction. This value should never be greater than 9_999_999 + int numDigitsRead = 0; + int fractionEnd = Math.Min( + sourceIndex + JsonConstants.DateTimeParseNumFractionDigits, + source.Length + ); + + while (sourceIndex < fractionEnd && IsDigit(curByte = source[sourceIndex])) + { + if (numDigitsRead < JsonConstants.DateTimeNumFractionDigits) + { + parseData.Fraction = parseData.Fraction * 10 + (int)(curByte - (uint)'0'); + numDigitsRead++; + } + + sourceIndex++; + } + + if (parseData.Fraction != 0) + { + while (numDigitsRead < JsonConstants.DateTimeNumFractionDigits) + { + parseData.Fraction *= 10; + numDigitsRead++; + } + } + + // We now have YYYY-MM-DDThh:mm:ss.s + Debug.Assert(sourceIndex <= source.Length); + if (sourceIndex == source.Length) + { + return true; + } + + curByte = source[sourceIndex++]; + + // TZD ['Z'|'+'|'-'] is valid at this point + switch (curByte) + { + case JsonConstants.UtcOffsetToken: + parseData.OffsetToken = JsonConstants.UtcOffsetToken; + return sourceIndex == source.Length; + case JsonConstants.Plus: + case JsonConstants.Hyphen: + parseData.OffsetToken = curByte; + return ParseOffset(ref parseData, source.Slice(sourceIndex)); + default: + return false; + } + + static bool ParseOffset(ref DateTimeParseData parseData, ReadOnlySpan offsetData) + { + // Parse the hours for the offset + if ( + offsetData.Length < 2 + || !TryGetNextTwoDigits(offsetData.Slice(0, 2), ref parseData.OffsetHours) + ) + { + return false; + } + + // We now have YYYY-MM-DDThh:mm:ss.s+|-hh + + if (offsetData.Length == 2) + { + // Just hours offset specified + return true; + } + + // Ensure we have enough for ":mm" + return offsetData.Length == 5 + && offsetData[2] == JsonConstants.Colon + && TryGetNextTwoDigits(offsetData.Slice(3), ref parseData.OffsetMinutes); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + // ReSharper disable once RedundantAssignment + private static bool TryGetNextTwoDigits(ReadOnlySpan source, ref int value) + { + Debug.Assert(source.Length == 2); + + uint digit1 = source[0] - (uint)'0'; + uint digit2 = source[1] - (uint)'0'; + + if (digit1 > 9 || digit2 > 9) + { + value = 0; + return false; + } + + value = (int)(digit1 * 10 + digit2); + return true; + } + + // The following methods are borrowed verbatim from src/Common/src/CoreLib/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.Helpers.cs + + /// + /// Overflow-safe DateTime factory. + /// + private static bool TryCreateDateTime( + DateTimeParseData parseData, + DateTimeKind kind, + out DateTime value + ) + { + if (parseData.Year == 0) + { + value = default; + return false; + } + + Debug.Assert(parseData.Year <= 9999); // All of our callers to date parse the year from fixed 4-digit fields so this value is trusted. + + if ((uint)parseData.Month - 1 >= 12) + { + value = default; + return false; + } + + uint dayMinusOne = (uint)parseData.Day - 1; + if ( + dayMinusOne >= 28 + && dayMinusOne >= DateTime.DaysInMonth(parseData.Year, parseData.Month) + ) + { + value = default; + return false; + } + + if ((uint)parseData.Hour > 23) + { + value = default; + return false; + } + + if ((uint)parseData.Minute > 59) + { + value = default; + return false; + } + + // This needs to allow leap seconds when appropriate. + // See https://github.com/dotnet/runtime/issues/30135. + if ((uint)parseData.Second > 59) + { + value = default; + return false; + } + + Debug.Assert(parseData.Fraction is >= 0 and <= JsonConstants.MaxDateTimeFraction); // All of our callers to date parse the fraction from fixed 7-digit fields so this value is trusted. + + ReadOnlySpan days = DateTime.IsLeapYear(parseData.Year) + ? DaysToMonth366 + : DaysToMonth365; + int yearMinusOne = parseData.Year - 1; + int totalDays = + yearMinusOne * 365 + + yearMinusOne / 4 + - yearMinusOne / 100 + + yearMinusOne / 400 + + days[parseData.Month - 1] + + parseData.Day + - 1; + long ticks = totalDays * TimeSpan.TicksPerDay; + int totalSeconds = parseData.Hour * 3600 + parseData.Minute * 60 + parseData.Second; + ticks += totalSeconds * TimeSpan.TicksPerSecond; + ticks += parseData.Fraction; + value = new DateTime(ticks: ticks, kind: kind); + return true; + } + + private static ReadOnlySpan DaysToMonth365 => + [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; + private static ReadOnlySpan DaysToMonth366 => + [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]; + } + + internal static class ThrowHelper + { + private const string ExceptionSourceValueToRethrowAsJsonException = + "System.Text.Json.Rethrowable"; + + [DoesNotReturn] + public static void ThrowInvalidOperationException_ExpectedString(JsonTokenType tokenType) + { + throw GetInvalidOperationException("string", tokenType); + } + + public static void ThrowFormatException(DataType dataType) + { + throw new FormatException(SR.Format(SR.UnsupportedFormat, dataType)) + { + Source = ExceptionSourceValueToRethrowAsJsonException, + }; + } + + private static global::System.Exception GetInvalidOperationException( + string message, + JsonTokenType tokenType + ) + { + return GetInvalidOperationException(SR.Format(SR.InvalidCast, tokenType, message)); + } + + private static InvalidOperationException GetInvalidOperationException(string message) + { + return new InvalidOperationException(message) + { + Source = ExceptionSourceValueToRethrowAsJsonException, + }; + } + } + + internal static class Utf8JsonReaderExtensions + { + internal static int ValueLength(this Utf8JsonReader reader) => + reader.HasValueSequence + ? checked((int)reader.ValueSequence.Length) + : reader.ValueSpan.Length; + } + + internal enum DataType + { + TimeOnly, + DateOnly, + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + internal static class SR + { + private static readonly bool s_usingResourceKeys = + AppContext.TryGetSwitch( + "System.Resources.UseSystemResourceKeys", + out bool usingResourceKeys + ) && usingResourceKeys; + + public static string UnsupportedFormat => Strings.UnsupportedFormat; + + public static string InvalidCast => Strings.InvalidCast; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static string Format(string resourceFormat, object? p1) => + s_usingResourceKeys + ? string.Join(", ", resourceFormat, p1) + : string.Format(resourceFormat, p1); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static string Format(string resourceFormat, object? p1, object? p2) => + s_usingResourceKeys + ? string.Join(", ", resourceFormat, p1, p2) + : string.Format(resourceFormat, p1, p2); + } + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute( + "System.Resources.Tools.StronglyTypedResourceBuilder", + "17.0.0.0" + )] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Strings + { + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute( + "Microsoft.Performance", + "CA1811:AvoidUncalledPrivateCode" + )] + internal Strings() { } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute( + global::System.ComponentModel.EditorBrowsableState.Advanced + )] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if (object.ReferenceEquals(resourceMan, null)) + { + global::System.Resources.ResourceManager temp = + new global::System.Resources.ResourceManager( + "System.Text.Json.Resources.Strings", + typeof(Strings).Assembly + ); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute( + global::System.ComponentModel.EditorBrowsableState.Advanced + )] + internal static global::System.Globalization.CultureInfo Culture + { + get { return resourceCulture; } + set { resourceCulture = value; } + } + + /// + /// Looks up a localized string similar to Cannot get the value of a token type '{0}' as a {1}.. + /// + internal static string InvalidCast + { + get { return ResourceManager.GetString("InvalidCast", resourceCulture); } + } + + /// + /// Looks up a localized string similar to The JSON value is not in a supported {0} format.. + /// + internal static string UnsupportedFormat + { + get { return ResourceManager.GetString("UnsupportedFormat", resourceCulture); } + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/DateTimeSerializer.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/DateTimeSerializer.cs new file mode 100644 index 000000000000..d2cdcefbbcfb --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/DateTimeSerializer.cs @@ -0,0 +1,40 @@ +using global::System.Globalization; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace SeedCsharpXmlEntities.Core; + +internal class DateTimeSerializer : JsonConverter +{ + public override DateTime Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + return DateTime.Parse(reader.GetString()!, null, DateTimeStyles.RoundtripKind); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString(Constants.DateTimeFormat)); + } + + public override DateTime ReadAsPropertyName( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + return DateTime.Parse(reader.GetString()!, null, DateTimeStyles.RoundtripKind); + } + + public override void WriteAsPropertyName( + Utf8JsonWriter writer, + DateTime value, + JsonSerializerOptions options + ) + { + writer.WritePropertyName(value.ToString(Constants.DateTimeFormat)); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/DefaultHttpClientFactory.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/DefaultHttpClientFactory.cs new file mode 100644 index 000000000000..f77fc76be50b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/DefaultHttpClientFactory.cs @@ -0,0 +1,25 @@ +using global::System.Net; +using global::System.Net.Http; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Creates the default used by the SDK, with automatic +/// response decompression enabled so that gzip/deflate encoded response bodies +/// are decompressed based on the response's Content-Encoding header. +/// +internal static class DefaultHttpClientFactory +{ + internal static HttpClient Create() + { + var handler = new HttpClientHandler + { +#if NET5_0_OR_GREATER + AutomaticDecompression = DecompressionMethods.All, +#else + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, +#endif + }; + return new HttpClient(handler); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/EmptyRequest.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/EmptyRequest.cs new file mode 100644 index 000000000000..4a2f72c48de4 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/EmptyRequest.cs @@ -0,0 +1,11 @@ +using global::System.Net.Http; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// The request object to send without a request body. +/// +internal record EmptyRequest : BaseRequest +{ + internal override HttpContent? CreateContent() => null; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/EncodingCache.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/EncodingCache.cs new file mode 100644 index 000000000000..91020ab27a68 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/EncodingCache.cs @@ -0,0 +1,11 @@ +using global::System.Text; + +namespace SeedCsharpXmlEntities.Core; + +internal static class EncodingCache +{ + internal static readonly Encoding Utf8NoBom = new UTF8Encoding( + encoderShouldEmitUTF8Identifier: false, + throwOnInvalidBytes: true + ); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Extensions.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Extensions.cs new file mode 100644 index 000000000000..dba70c9670ae --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Extensions.cs @@ -0,0 +1,57 @@ +using global::System.Diagnostics.CodeAnalysis; +using global::System.Runtime.Serialization; + +namespace SeedCsharpXmlEntities.Core; + +internal static class Extensions +{ + public static string Stringify(this Enum value) + { + var field = value.GetType().GetField(value.ToString()); + if (field is not null) + { + var attribute = (EnumMemberAttribute?) + global::System.Attribute.GetCustomAttribute(field, typeof(EnumMemberAttribute)); + return attribute?.Value ?? value.ToString(); + } + return value.ToString(); + } + + /// + /// Asserts that a condition is true, throwing an exception with the specified message if it is false. + /// + /// The object the extension method is invoked on; unused. + /// The condition to assert. + /// The exception message if the assertion fails. + /// Thrown when the condition is false. + internal static void Assert(this object value, bool condition, string message) + { + if (!condition) + { + throw new global::System.Exception(message); + } + } + + /// + /// Asserts that a value is not null, throwing an exception with the specified message if it is null. + /// + /// The type of the value to assert. + /// The object the extension method is invoked on; unused. + /// The value to assert is not null. + /// The exception message if the assertion fails. + /// The non-null value. + /// Thrown when the value is null. + internal static TValue Assert( + this object _unused, + [NotNull] TValue? value, + string message + ) + where TValue : class + { + if (value is null) + { + throw new global::System.Exception(message); + } + return value; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/FormUrlEncoder.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/FormUrlEncoder.cs new file mode 100644 index 000000000000..679968707a8f --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/FormUrlEncoder.cs @@ -0,0 +1,33 @@ +using global::System.Net.Http; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Encodes an object into a form URL-encoded content. +/// +public static class FormUrlEncoder +{ + /// + /// Encodes an object into a form URL-encoded content using Deep Object notation. + /// + /// Object to form URL-encode. You can pass in an object or dictionary, but not lists, strings, or primitives. + /// Throws when passing in a list, a string, or a primitive value. + internal static FormUrlEncodedContent EncodeAsDeepObject(object value) => + new(QueryStringConverter.ToDeepObject(value)); + + /// + /// Encodes an object into a form URL-encoded content using Exploded Form notation. + /// + /// Object to form URL-encode. You can pass in an object or dictionary, but not lists, strings, or primitives. + /// Throws when passing in a list, a string, or a primitive value. + internal static FormUrlEncodedContent EncodeAsExplodedForm(object value) => + new(QueryStringConverter.ToExplodedForm(value)); + + /// + /// Encodes an object into a form URL-encoded content using Form notation without exploding parameters. + /// + /// Object to form URL-encode. You can pass in an object or dictionary, but not lists, strings, or primitives. + /// Throws when passing in a list, a string, or a primitive value. + internal static FormUrlEncodedContent EncodeAsForm(object value) => + new(QueryStringConverter.ToForm(value)); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HeaderValue.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HeaderValue.cs new file mode 100644 index 000000000000..59f4e01adcd9 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HeaderValue.cs @@ -0,0 +1,52 @@ +namespace SeedCsharpXmlEntities.Core; + +internal sealed class HeaderValue +{ + private readonly Func> _resolver; + + public HeaderValue(string value) + { + _resolver = () => new global::System.Threading.Tasks.ValueTask(value); + } + + public HeaderValue(Func value) + { + _resolver = () => new global::System.Threading.Tasks.ValueTask(value()); + } + + public HeaderValue(Func> value) + { + _resolver = value; + } + + public HeaderValue(Func> value) + { + _resolver = () => new global::System.Threading.Tasks.ValueTask(value()); + } + + public static implicit operator HeaderValue(string value) => new(value); + + public static implicit operator HeaderValue(Func value) => new(value); + + public static implicit operator HeaderValue( + Func> value + ) => new(value); + + public static implicit operator HeaderValue( + Func> value + ) => new(value); + + public static HeaderValue FromString(string value) => new(value); + + public static HeaderValue FromFunc(Func value) => new(value); + + public static HeaderValue FromValueTaskFunc( + Func> value + ) => new(value); + + public static HeaderValue FromTaskFunc( + Func> value + ) => new(value); + + internal global::System.Threading.Tasks.ValueTask ResolveAsync() => _resolver(); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Headers.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Headers.cs new file mode 100644 index 000000000000..17f7dd4517a6 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Headers.cs @@ -0,0 +1,28 @@ +namespace SeedCsharpXmlEntities.Core; + +/// +/// Represents the headers sent with the request. +/// +internal sealed class Headers : Dictionary +{ + internal Headers() { } + + /// + /// Initializes a new instance of the Headers class with the specified value. + /// + /// + internal Headers(Dictionary value) + { + foreach (var kvp in value) + { + this[kvp.Key] = kvp.Value; + } + } + + /// + /// Initializes a new instance of the Headers class with the specified value. + /// + /// + internal Headers(IEnumerable> value) + : base(value.ToDictionary(e => e.Key, e => e.Value)) { } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HeadersBuilder.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HeadersBuilder.cs new file mode 100644 index 000000000000..4893ea05b4c4 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HeadersBuilder.cs @@ -0,0 +1,197 @@ +namespace SeedCsharpXmlEntities.Core; + +/// +/// Fluent builder for constructing HTTP headers with support for merging from multiple sources. +/// Provides a clean API for building headers with proper precedence handling. +/// +internal static class HeadersBuilder +{ + /// + /// Fluent builder for constructing HTTP headers. + /// + public sealed class Builder + { + private readonly Dictionary _headers; + + /// + /// Initializes a new instance with default capacity. + /// Uses case-insensitive header name comparison. + /// + public Builder() + { + _headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + /// + /// Initializes a new instance with the specified initial capacity. + /// Uses case-insensitive header name comparison. + /// + public Builder(int capacity) + { + _headers = new Dictionary( + capacity, + StringComparer.OrdinalIgnoreCase + ); + } + + /// + /// Adds a header with the specified key and value. + /// If a header with the same key already exists, it will be overwritten. + /// Null values are ignored. + /// + /// The header name. + /// The header value. Null values are ignored. + /// This builder instance for method chaining. + public Builder Add(string key, string? value) + { + if (value is not null) + { + _headers[key] = (value); + } + return this; + } + + /// + /// Adds a header with the specified key and object value. + /// The value will be converted to string using ValueConvert for consistent serialization. + /// If a header with the same key already exists, it will be overwritten. + /// Null values are ignored. + /// + /// The header name. + /// The header value. Null values are ignored. + /// This builder instance for method chaining. + public Builder Add(string key, object? value) + { + if (value is null) + { + return this; + } + + // Use ValueConvert for consistent serialization across headers, query params, and path params + var stringValue = ValueConvert.ToString(value); + if (stringValue is not null) + { + _headers[key] = (stringValue); + } + return this; + } + + /// + /// Adds multiple headers from a Headers dictionary. + /// HeaderValue instances are stored and will be resolved when BuildAsync() is called. + /// Overwrites any existing headers with the same key. + /// Null entries are ignored. + /// + /// The headers to add. Null is treated as empty. + /// This builder instance for method chaining. + public Builder Add(Headers? headers) + { + if (headers is null) + { + return this; + } + + foreach (var header in headers) + { + _headers[header.Key] = header.Value; + } + + return this; + } + + /// + /// Adds multiple headers from a Headers dictionary, excluding the Authorization header. + /// This is useful for endpoints that don't require authentication, to avoid triggering + /// lazy auth token resolution. + /// HeaderValue instances are stored and will be resolved when BuildAsync() is called. + /// Overwrites any existing headers with the same key. + /// Null entries are ignored. + /// + /// The headers to add. Null is treated as empty. + /// This builder instance for method chaining. + public Builder AddWithoutAuth(Headers? headers) + { + if (headers is null) + { + return this; + } + + foreach (var header in headers) + { + if (header.Key.Equals("Authorization", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + _headers[header.Key] = header.Value; + } + + return this; + } + + /// + /// Adds multiple headers from a key-value pair collection. + /// Overwrites any existing headers with the same key. + /// Null values are ignored. + /// + /// The headers to add. Null is treated as empty. + /// This builder instance for method chaining. + public Builder Add(IEnumerable>? headers) + { + if (headers is null) + { + return this; + } + + foreach (var header in headers) + { + if (header.Value is not null) + { + _headers[header.Key] = (header.Value); + } + } + + return this; + } + + /// + /// Adds multiple headers from a dictionary. + /// Overwrites any existing headers with the same key. + /// + /// The headers to add. Null is treated as empty. + /// This builder instance for method chaining. + public Builder Add(Dictionary? headers) + { + if (headers is null) + { + return this; + } + + foreach (var header in headers) + { + _headers[header.Key] = (header.Value); + } + + return this; + } + + /// + /// Asynchronously builds the final headers dictionary containing all merged headers. + /// Resolves all HeaderValue instances that may contain async operations. + /// Returns a case-insensitive dictionary. + /// + /// A task that represents the asynchronous operation, containing a case-insensitive dictionary of headers. + public async global::System.Threading.Tasks.Task> BuildAsync() + { + var headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var kvp in _headers) + { + var value = await kvp.Value.ResolveAsync().ConfigureAwait(false); + if (value is not null) + { + headers[kvp.Key] = value; + } + } + return headers; + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HttpContentExtensions.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HttpContentExtensions.cs new file mode 100644 index 000000000000..b277051bd81d --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HttpContentExtensions.cs @@ -0,0 +1,20 @@ +#if !NET5_0_OR_GREATER +namespace SeedCsharpXmlEntities.Core; + +/// +/// Polyfill extension providing a ReadAsStringAsync(CancellationToken) overload +/// for target frameworks older than .NET 5, where only the parameterless +/// ReadAsStringAsync() is available. +/// +internal static class HttpContentExtensions +{ + internal static Task ReadAsStringAsync( + this HttpContent httpContent, + CancellationToken cancellationToken + ) + { + cancellationToken.ThrowIfCancellationRequested(); + return httpContent.ReadAsStringAsync(); + } +} +#endif diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HttpMethodExtensions.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HttpMethodExtensions.cs new file mode 100644 index 000000000000..09ebd779bde7 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/HttpMethodExtensions.cs @@ -0,0 +1,8 @@ +using global::System.Net.Http; + +namespace SeedCsharpXmlEntities.Core; + +internal static class HttpMethodExtensions +{ + public static readonly HttpMethod Patch = new("PATCH"); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/IIsRetryableContent.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/IIsRetryableContent.cs new file mode 100644 index 000000000000..1c3fc7b5e1c2 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/IIsRetryableContent.cs @@ -0,0 +1,6 @@ +namespace SeedCsharpXmlEntities.Core; + +public interface IIsRetryableContent +{ + public bool IsRetryable { get; } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/IRequestOptions.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/IRequestOptions.cs new file mode 100644 index 000000000000..0f818aa724cb --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/IRequestOptions.cs @@ -0,0 +1,83 @@ +namespace SeedCsharpXmlEntities.Core; + +internal interface IRequestOptions +{ + /// + /// The Base URL for the API. + /// + public string? BaseUrl { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// The http client used to make requests. + /// + public HttpClient? HttpClient { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// Additional headers to be sent with the request. + /// Headers previously set with matching keys will be overwritten. + /// + public IEnumerable> AdditionalHeaders { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// The max number of retries to attempt. + /// + public int? MaxRetries { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// The timeout for the request. + /// + public TimeSpan? Timeout { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// Additional query parameters sent with the request. + /// + public IEnumerable> AdditionalQueryParameters { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// Additional body properties sent with the request. + /// This is only applied to JSON requests. + /// + public object? AdditionalBodyProperties { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/JsonAccessAttribute.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/JsonAccessAttribute.cs new file mode 100644 index 000000000000..c2e49dc5d92b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/JsonAccessAttribute.cs @@ -0,0 +1,15 @@ +namespace SeedCsharpXmlEntities.Core; + +[global::System.AttributeUsage( + global::System.AttributeTargets.Property | global::System.AttributeTargets.Field +)] +internal class JsonAccessAttribute(JsonAccessType accessType) : global::System.Attribute +{ + internal JsonAccessType AccessType { get; init; } = accessType; +} + +internal enum JsonAccessType +{ + ReadOnly, + WriteOnly, +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/JsonConfiguration.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/JsonConfiguration.cs new file mode 100644 index 000000000000..684697dcceca --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/JsonConfiguration.cs @@ -0,0 +1,275 @@ +using global::System.Reflection; +using global::System.Text.Encodings.Web; +using global::System.Text.Json; +using global::System.Text.Json.Nodes; +using global::System.Text.Json.Serialization; +using global::System.Text.Json.Serialization.Metadata; + +namespace SeedCsharpXmlEntities.Core; + +internal static partial class JsonOptions +{ + internal static readonly JsonSerializerOptions JsonSerializerOptions; + internal static readonly JsonSerializerOptions JsonSerializerOptionsRelaxedEscaping; + + static JsonOptions() + { + var options = new JsonSerializerOptions + { + Converters = + { + new DateTimeSerializer(), +#if USE_PORTABLE_DATE_ONLY + new DateOnlyConverter(), +#endif + new OneOfSerializer(), + new OptionalJsonConverterFactory(), + }, +#if DEBUG + WriteIndented = true, +#endif + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + TypeInfoResolver = new DefaultJsonTypeInfoResolver + { + Modifiers = + { + NullableOptionalModifier, + JsonAccessAndIgnoreModifier, + HandleExtensionDataFields, + }, + }, + }; + ConfigureJsonSerializerOptions(options); + JsonSerializerOptions = options; + + var relaxedOptions = new JsonSerializerOptions(options) + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + }; + JsonSerializerOptionsRelaxedEscaping = relaxedOptions; + } + + private static void NullableOptionalModifier(JsonTypeInfo typeInfo) + { + if (typeInfo.Kind != JsonTypeInfoKind.Object) + return; + + foreach (var property in typeInfo.Properties) + { + var propertyInfo = property.AttributeProvider as global::System.Reflection.PropertyInfo; + + if (propertyInfo is null) + continue; + + // Check for ReadOnly JsonAccessAttribute - it overrides Optional/Nullable behavior + var jsonAccessAttribute = propertyInfo.GetCustomAttribute(); + if (jsonAccessAttribute?.AccessType == JsonAccessType.ReadOnly) + { + // ReadOnly means "never serialize", which completely overrides Optional/Nullable. + // Skip Optional/Nullable processing since JsonAccessAndIgnoreModifier + // will set ShouldSerialize = false anyway. + continue; + } + // Note: WriteOnly doesn't conflict with Optional/Nullable since it only + // affects deserialization (Set), not serialization (ShouldSerialize) + + var isOptionalType = + property.PropertyType.IsGenericType + && property.PropertyType.GetGenericTypeDefinition() == typeof(Optional<>); + + var hasOptionalAttribute = + propertyInfo.GetCustomAttribute() is not null; + var hasNullableAttribute = + propertyInfo.GetCustomAttribute() is not null; + + if (isOptionalType && hasOptionalAttribute) + { + var originalGetter = property.Get; + if (originalGetter is not null) + { + var capturedIsNullable = hasNullableAttribute; + + property.ShouldSerialize = (obj, value) => + { + var optionalValue = originalGetter(obj); + if (optionalValue is not IOptional optional) + return false; + + if (!optional.IsDefined) + return false; + + if (!capturedIsNullable) + { + var innerValue = optional.GetBoxedValue(); + if (innerValue is null) + return false; + } + + return true; + }; + } + } + else if (hasNullableAttribute) + { + // Force serialization of nullable properties even when null + property.ShouldSerialize = (obj, value) => true; + } + } + } + + private static void JsonAccessAndIgnoreModifier(JsonTypeInfo typeInfo) + { + if (typeInfo.Kind != JsonTypeInfoKind.Object) + return; + + foreach (var propertyInfo in typeInfo.Properties) + { + var jsonAccessAttribute = propertyInfo + .AttributeProvider?.GetCustomAttributes(typeof(JsonAccessAttribute), true) + .OfType() + .FirstOrDefault(); + + if (jsonAccessAttribute is not null) + { + propertyInfo.IsRequired = false; + switch (jsonAccessAttribute.AccessType) + { + case JsonAccessType.ReadOnly: + propertyInfo.ShouldSerialize = (_, _) => false; + break; + case JsonAccessType.WriteOnly: + propertyInfo.Set = null; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + var jsonIgnoreAttribute = propertyInfo + .AttributeProvider?.GetCustomAttributes(typeof(JsonIgnoreAttribute), true) + .OfType() + .FirstOrDefault(); + + if (jsonIgnoreAttribute is not null) + { + propertyInfo.IsRequired = false; + } + } + } + + private static void HandleExtensionDataFields(JsonTypeInfo typeInfo) + { + if ( + typeInfo.Kind == JsonTypeInfoKind.Object + && typeInfo.Properties.All(prop => !prop.IsExtensionData) + ) + { + var extensionProp = typeInfo + .Type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic) + .FirstOrDefault(prop => + prop.GetCustomAttribute() is not null + ); + + if (extensionProp is not null) + { + var jsonPropertyInfo = typeInfo.CreateJsonPropertyInfo( + extensionProp.FieldType, + extensionProp.Name + ); + jsonPropertyInfo.Get = extensionProp.GetValue; + jsonPropertyInfo.Set = extensionProp.SetValue; + jsonPropertyInfo.IsExtensionData = true; + typeInfo.Properties.Add(jsonPropertyInfo); + } + } + } + + static partial void ConfigureJsonSerializerOptions(JsonSerializerOptions defaultOptions); +} + +internal static class JsonUtils +{ + internal static string Serialize(T obj) => + JsonSerializer.Serialize(obj, JsonOptions.JsonSerializerOptions); + + internal static string Serialize(object obj, global::System.Type type) => + JsonSerializer.Serialize(obj, type, JsonOptions.JsonSerializerOptions); + + internal static string SerializeRelaxedEscaping(T obj) => + JsonSerializer.Serialize(obj, JsonOptions.JsonSerializerOptionsRelaxedEscaping); + + internal static string SerializeRelaxedEscaping(object obj, global::System.Type type) => + JsonSerializer.Serialize(obj, type, JsonOptions.JsonSerializerOptionsRelaxedEscaping); + + internal static JsonElement SerializeToElement(T obj) => + JsonSerializer.SerializeToElement(obj, JsonOptions.JsonSerializerOptions); + + internal static JsonElement SerializeToElement(object obj, global::System.Type type) => + JsonSerializer.SerializeToElement(obj, type, JsonOptions.JsonSerializerOptions); + + internal static JsonDocument SerializeToDocument(T obj) => + JsonSerializer.SerializeToDocument(obj, JsonOptions.JsonSerializerOptions); + + internal static JsonNode? SerializeToNode(T obj) => + JsonSerializer.SerializeToNode(obj, JsonOptions.JsonSerializerOptions); + + internal static byte[] SerializeToUtf8Bytes(T obj) => + JsonSerializer.SerializeToUtf8Bytes(obj, JsonOptions.JsonSerializerOptions); + + internal static string SerializeWithAdditionalProperties( + T obj, + object? additionalProperties = null + ) + { + if (additionalProperties is null) + { + return Serialize(obj); + } + var additionalPropertiesJsonNode = SerializeToNode(additionalProperties); + if (additionalPropertiesJsonNode is not JsonObject additionalPropertiesJsonObject) + { + throw new InvalidOperationException( + "The additional properties must serialize to a JSON object." + ); + } + var jsonNode = SerializeToNode(obj); + if (jsonNode is not JsonObject jsonObject) + { + throw new InvalidOperationException( + "The serialized object must be a JSON object to add properties." + ); + } + MergeJsonObjects(jsonObject, additionalPropertiesJsonObject); + return jsonObject.ToJsonString(JsonOptions.JsonSerializerOptions); + } + + private static void MergeJsonObjects(JsonObject baseObject, JsonObject overrideObject) + { + foreach (var property in overrideObject) + { + if (!baseObject.TryGetPropertyValue(property.Key, out JsonNode? existingValue)) + { + baseObject[property.Key] = property.Value is not null + ? JsonNode.Parse(property.Value.ToJsonString()) + : null; + continue; + } + if ( + existingValue is JsonObject nestedBaseObject + && property.Value is JsonObject nestedOverrideObject + ) + { + // If both values are objects, recursively merge them. + MergeJsonObjects(nestedBaseObject, nestedOverrideObject); + continue; + } + // Otherwise, the overrideObject takes precedence. + baseObject[property.Key] = property.Value is not null + ? JsonNode.Parse(property.Value.ToJsonString()) + : null; + } + } + + internal static T Deserialize(string json) => + JsonSerializer.Deserialize(json, JsonOptions.JsonSerializerOptions)!; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/JsonRequest.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/JsonRequest.cs new file mode 100644 index 000000000000..d7794d7ba46b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/JsonRequest.cs @@ -0,0 +1,36 @@ +using global::System.Net.Http; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// The request object to be sent for JSON APIs. +/// +internal record JsonRequest : BaseRequest +{ + internal object? Body { get; init; } + + internal override HttpContent? CreateContent() + { + if (Body is null && Options?.AdditionalBodyProperties is null) + { + return null; + } + + var (encoding, charset, mediaType) = ParseContentTypeOrDefault( + ContentType, + Utf8NoBom, + "application/json" + ); + var content = new StringContent( + JsonUtils.SerializeWithAdditionalProperties(Body, Options?.AdditionalBodyProperties), + encoding, + mediaType + ); + if (string.IsNullOrEmpty(charset) && content.Headers.ContentType is not null) + { + content.Headers.ContentType.CharSet = ""; + } + + return content; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/MultipartFormRequest.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/MultipartFormRequest.cs new file mode 100644 index 000000000000..41654f9c09e1 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/MultipartFormRequest.cs @@ -0,0 +1,294 @@ +using global::System.Net.Http; +using global::System.Net.Http.Headers; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// The request object to be sent for multipart form data. +/// +internal record MultipartFormRequest : BaseRequest +{ + private readonly List> _partAdders = []; + + internal void AddJsonPart(string name, object? value) => AddJsonPart(name, value, null); + + internal void AddJsonPart(string name, object? value, string? contentType) + { + if (value is null) + { + return; + } + + _partAdders.Add(form => + { + var (encoding, charset, mediaType) = ParseContentTypeOrDefault( + contentType, + Utf8NoBom, + "application/json" + ); + var content = new StringContent(JsonUtils.Serialize(value), encoding, mediaType); + if (string.IsNullOrEmpty(charset) && content.Headers.ContentType is not null) + { + content.Headers.ContentType.CharSet = ""; + } + + form.Add(content, name); + }); + } + + internal void AddJsonParts(string name, IEnumerable? value) => + AddJsonParts(name, value, null); + + internal void AddJsonParts(string name, IEnumerable? value, string? contentType) + { + if (value is null) + { + return; + } + + foreach (var item in value) + { + AddJsonPart(name, item, contentType); + } + } + + internal void AddJsonParts(string name, IEnumerable? value) => + AddJsonParts(name, value, null); + + internal void AddJsonParts(string name, IEnumerable? value, string? contentType) + { + if (value is null) + { + return; + } + + foreach (var item in value) + { + AddJsonPart(name, item, contentType); + } + } + + internal void AddStringPart(string name, object? value) => AddStringPart(name, value, null); + + internal void AddStringPart(string name, object? value, string? contentType) + { + if (value is null) + { + return; + } + + AddStringPart(name, ValueConvert.ToString(value), contentType); + } + + internal void AddStringPart(string name, string? value) => AddStringPart(name, value, null); + + internal void AddStringPart(string name, string? value, string? contentType) + { + if (value is null) + { + return; + } + + _partAdders.Add(form => + { + var (encoding, charset, mediaType) = ParseContentTypeOrDefault( + contentType, + Utf8NoBom, + "text/plain" + ); + var content = new StringContent(value, encoding, mediaType); + if (string.IsNullOrEmpty(charset) && content.Headers.ContentType is not null) + { + content.Headers.ContentType.CharSet = ""; + } + + form.Add(content, name); + }); + } + + internal void AddStringParts(string name, IEnumerable? value) => + AddStringParts(name, value, null); + + internal void AddStringParts(string name, IEnumerable? value, string? contentType) + { + if (value is null) + { + return; + } + + AddStringPart(name, ValueConvert.ToString(value), contentType); + } + + internal void AddStringParts(string name, IEnumerable? value) => + AddStringParts(name, value, null); + + internal void AddStringParts(string name, IEnumerable? value, string? contentType) + { + if (value is null) + { + return; + } + + foreach (var item in value) + { + AddStringPart(name, item, contentType); + } + } + + internal void AddStreamPart(string name, Stream? stream, string? fileName) => + AddStreamPart(name, stream, fileName, null); + + internal void AddStreamPart(string name, Stream? stream, string? fileName, string? contentType) + { + if (stream is null) + { + return; + } + + _partAdders.Add(form => + { + var content = new StreamContent(stream) + { + Headers = + { + ContentType = MediaTypeHeaderValue.Parse( + contentType ?? "application/octet-stream" + ), + }, + }; + + if (fileName is not null) + { + form.Add(content, name, fileName); + } + else + { + form.Add(content, name); + } + }); + } + + internal void AddFileParameterPart(string name, Stream? stream) => + AddStreamPart(name, stream, null, null); + + internal void AddFileParameterPart(string name, FileParameter? file) => + AddFileParameterPart(name, file, null); + + internal void AddFileParameterPart( + string name, + FileParameter? file, + string? fallbackContentType + ) => + AddStreamPart(name, file?.Stream, file?.FileName, file?.ContentType ?? fallbackContentType); + + internal void AddFileParameterParts(string name, IEnumerable? files) => + AddFileParameterParts(name, files, null); + + internal void AddFileParameterParts( + string name, + IEnumerable? files, + string? fallbackContentType + ) + { + if (files is null) + { + return; + } + + foreach (var file in files) + { + AddFileParameterPart(name, file, fallbackContentType); + } + } + + internal void AddFormEncodedPart(string name, object? value) => + AddFormEncodedPart(name, value, null); + + internal void AddFormEncodedPart(string name, object? value, string? contentType) + { + if (value is null) + { + return; + } + + _partAdders.Add(form => + { + var content = FormUrlEncoder.EncodeAsForm(value); + if (!string.IsNullOrEmpty(contentType)) + { + content.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType); + } + + form.Add(content, name); + }); + } + + internal void AddFormEncodedParts(string name, IEnumerable? value) => + AddFormEncodedParts(name, value, null); + + internal void AddFormEncodedParts(string name, IEnumerable? value, string? contentType) + { + if (value is null) + { + return; + } + + foreach (var item in value) + { + AddFormEncodedPart(name, item, contentType); + } + } + + internal void AddExplodedFormEncodedPart(string name, object? value) => + AddExplodedFormEncodedPart(name, value, null); + + internal void AddExplodedFormEncodedPart(string name, object? value, string? contentType) + { + if (value is null) + { + return; + } + + _partAdders.Add(form => + { + var content = FormUrlEncoder.EncodeAsExplodedForm(value); + if (!string.IsNullOrEmpty(contentType)) + { + content.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType); + } + + form.Add(content, name); + }); + } + + internal void AddExplodedFormEncodedParts(string name, IEnumerable? value) => + AddExplodedFormEncodedParts(name, value, null); + + internal void AddExplodedFormEncodedParts( + string name, + IEnumerable? value, + string? contentType + ) + { + if (value is null) + { + return; + } + + foreach (var item in value) + { + AddExplodedFormEncodedPart(name, item, contentType); + } + } + + internal override HttpContent CreateContent() + { + var form = new MultipartFormDataContent(); + foreach (var adder in _partAdders) + { + adder(form); + } + + return form; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/NullableAttribute.cs new file mode 100644 index 000000000000..4f8c34c7dcd3 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/NullableAttribute.cs @@ -0,0 +1,18 @@ +namespace SeedCsharpXmlEntities.Core; + +/// +/// Marks a property as nullable in the OpenAPI specification. +/// When applied to Optional<T> properties, this indicates that null values should be +/// written to JSON when the optional is defined with null. +/// +/// +/// For regular (required) properties: +/// - Without [Nullable]: null values are invalid (omit from JSON at runtime) +/// - With [Nullable]: null values are written to JSON +/// +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON +/// +[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] +public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/OneOfSerializer.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/OneOfSerializer.cs new file mode 100644 index 000000000000..2dd8f5915427 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/OneOfSerializer.cs @@ -0,0 +1,190 @@ +using global::System.Reflection; +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using OneOf; + +namespace SeedCsharpXmlEntities.Core; + +internal class OneOfSerializer : JsonConverter +{ + public override IOneOf? Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType is JsonTokenType.Null) + return default; + + var json = JsonElement.ParseValue(ref reader); + + IOneOf? firstMatch = null; + IOneOf? bestMatch = null; + + foreach (var (type, cast) in GetOneOfTypes(typeToConvert)) + { + try + { + var result = JsonSerializer.Deserialize(json, type, options); + var oneOf = (IOneOf)cast.Invoke(null, [result])!; + firstMatch ??= oneOf; + + if (!ContainsJsonElement(result)) + { + bestMatch = oneOf; + break; + } + } + catch (JsonException) { } + } + + return bestMatch + ?? firstMatch + ?? throw new JsonException( + $"Cannot deserialize into one of the supported types for {typeToConvert}" + ); + } + + /// + /// Checks if the deserialized object is or contains a raw JsonElement value, + /// indicating the deserializer used a catch-all strategy rather than + /// strongly-typed deserialization. + /// + private static bool ContainsJsonElement(object? result) + { + if (result == null || result is JsonElement) + return true; + + foreach ( + var prop in result.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance) + ) + { + if (prop.GetCustomAttribute() != null) + continue; + if (prop.GetCustomAttribute() != null) + continue; + + try + { + if (prop.GetValue(result) is JsonElement) + return true; + } + catch + { + // Ignore inaccessible properties + } + } + + return false; + } + + public override void Write(Utf8JsonWriter writer, IOneOf value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value.Value, options); + } + + public override IOneOf ReadAsPropertyName( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + var stringValue = reader.GetString(); + if (stringValue == null) + throw new JsonException("Cannot deserialize null property name into OneOf type"); + + // Try to deserialize the string value into one of the supported types + foreach (var (type, cast) in GetOneOfTypes(typeToConvert)) + { + try + { + // For primitive types, try direct conversion + if (type == typeof(string)) + { + return (IOneOf)cast.Invoke(null, [stringValue])!; + } + + // For other types, try to deserialize from JSON string + var result = JsonSerializer.Deserialize($"\"{stringValue}\"", type, options); + if (result != null) + { + return (IOneOf)cast.Invoke(null, [result])!; + } + } + catch { } + } + + // If no type-specific deserialization worked, default to string if available + var stringType = GetOneOfTypes(typeToConvert).FirstOrDefault(t => t.type == typeof(string)); + if (stringType != default) + { + return (IOneOf)stringType.cast.Invoke(null, [stringValue])!; + } + + throw new JsonException( + $"Cannot deserialize dictionary key '{stringValue}' into one of the supported types for {typeToConvert}" + ); + } + + public override void WriteAsPropertyName( + Utf8JsonWriter writer, + IOneOf value, + JsonSerializerOptions options + ) + { + // Serialize the underlying value to a string suitable for use as a dictionary key + var stringValue = value.Value?.ToString() ?? "null"; + writer.WritePropertyName(stringValue); + } + + private static (global::System.Type type, MethodInfo cast)[] GetOneOfTypes( + global::System.Type typeToConvert + ) + { + var type = typeToConvert; + if (Nullable.GetUnderlyingType(type) is { } underlyingType) + { + type = underlyingType; + } + + var casts = type.GetRuntimeMethods() + .Where(m => m.IsSpecialName && m.Name == "op_Implicit") + .ToArray(); + while (type is not null) + { + if ( + type.IsGenericType + && (type.Name.StartsWith("OneOf`") || type.Name.StartsWith("OneOfBase`")) + ) + { + var genericArguments = type.GetGenericArguments(); + if (genericArguments.Length == 1) + { + return [(genericArguments[0], casts[0])]; + } + + // if object type is present, make sure it is last + var indexOfObjectType = Array.IndexOf(genericArguments, typeof(object)); + if (indexOfObjectType != -1 && genericArguments.Length - 1 != indexOfObjectType) + { + genericArguments = genericArguments + .OrderBy(t => t == typeof(object) ? 1 : 0) + .ToArray(); + } + + return genericArguments + .Select(t => (t, casts.First(c => c.GetParameters()[0].ParameterType == t))) + .ToArray(); + } + + type = type.BaseType; + } + + throw new InvalidOperationException($"{type} isn't OneOf or OneOfBase"); + } + + public override bool CanConvert(global::System.Type typeToConvert) + { + return typeof(IOneOf).IsAssignableFrom(typeToConvert); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Optional.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Optional.cs new file mode 100644 index 000000000000..2643c552ec69 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Optional.cs @@ -0,0 +1,474 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Non-generic interface for Optional types to enable reflection-free checks. +/// +public interface IOptional +{ + /// + /// Returns true if the value is defined (set), even if the value is null. + /// + bool IsDefined { get; } + + /// + /// Gets the boxed value. Returns null if undefined or if the value is null. + /// + object? GetBoxedValue(); +} + +/// +/// Represents a field that can be "not set" (undefined) vs "explicitly set" (defined). +/// Use this for HTTP PATCH requests where you need to distinguish between: +/// +/// Undefined: Don't send this field (leave it unchanged on the server) +/// Defined with null: Send null (clear the field on the server) +/// Defined with value: Send the value (update the field on the server) +/// +/// +/// The type of the value. Use nullable types (T?) for fields that can be null. +/// +/// For nullable string fields, use Optional<string?>: +/// +/// public class UpdateUserRequest +/// { +/// public Optional<string?> Name { get; set; } = Optional<string?>.Undefined; +/// } +/// +/// var request = new UpdateUserRequest +/// { +/// Name = "John" // Will send: { "name": "John" } +/// }; +/// +/// var request2 = new UpdateUserRequest +/// { +/// Name = Optional<string?>.Of(null) // Will send: { "name": null } +/// }; +/// +/// var request3 = new UpdateUserRequest(); // Will send: {} (name not included) +/// +/// +public readonly struct Optional : IOptional, IEquatable> +{ + private readonly T _value; + private readonly bool _isDefined; + + private Optional(T value, bool isDefined) + { + _value = value; + _isDefined = isDefined; + } + + /// + /// Creates an undefined value - the field will not be included in the HTTP request. + /// Use this as the default value for optional fields. + /// + /// + /// + /// public Optional<string?> Email { get; set; } = Optional<string?>.Undefined; + /// + /// + public static Optional Undefined => new(default!, false); + + /// + /// Creates a defined value - the field will be included in the HTTP request. + /// The value can be null if T is a nullable type. + /// + /// The value to set. Can be null if T is nullable (e.g., string?, int?). + /// + /// + /// // Set to a value + /// request.Name = Optional<string?>.Of("John"); + /// + /// // Set to null (clears the field) + /// request.Email = Optional<string?>.Of(null); + /// + /// // Or use implicit conversion + /// request.Name = "John"; // Same as Of("John") + /// request.Email = null; // Same as Of(null) + /// + /// + public static Optional Of(T value) => new(value, true); + + /// + /// Returns true if the field is defined (set), even if the value is null. + /// Use this to determine if the field should be included in the HTTP request. + /// + /// + /// + /// if (request.Name.IsDefined) + /// { + /// requestBody["name"] = request.Name.Value; // Include in request (can be null) + /// } + /// + /// + public bool IsDefined => _isDefined; + + /// + /// Returns true if the field is undefined (not set). + /// Use this to check if the field should be excluded from the HTTP request. + /// + /// + /// + /// if (request.Email.IsUndefined) + /// { + /// // Don't include email in the request - leave it unchanged + /// } + /// + /// + public bool IsUndefined => !_isDefined; + + /// + /// Gets the value. The value may be null if T is a nullable type. + /// + /// Thrown if the value is undefined. + /// + /// Always check before accessing Value, or use instead. + /// + /// + /// + /// if (request.Name.IsDefined) + /// { + /// string? name = request.Name.Value; // Safe - can be null if Optional<string?> + /// } + /// + /// // Or check for null explicitly + /// if (request.Email.IsDefined && request.Email.Value is null) + /// { + /// // Email is explicitly set to null (clear it) + /// } + /// + /// + public T Value + { + get + { + if (!_isDefined) + throw new InvalidOperationException("Optional value is undefined"); + return _value; + } + } + + /// + /// Gets the value if defined, otherwise returns the specified default value. + /// Note: If the value is defined as null, this returns null (not the default). + /// + /// The value to return if undefined. + /// The actual value if defined (can be null), otherwise the default value. + /// + /// + /// string name = request.Name.GetValueOrDefault("Anonymous"); + /// // If Name is undefined: returns "Anonymous" + /// // If Name is Of(null): returns null + /// // If Name is Of("John"): returns "John" + /// + /// + public T GetValueOrDefault(T defaultValue = default!) + { + return _isDefined ? _value : defaultValue; + } + + /// + /// Tries to get the value. Returns true if the value is defined (even if null). + /// + /// + /// When this method returns, contains the value if defined, or default(T) if undefined. + /// The value may be null if T is nullable. + /// + /// True if the value is defined; otherwise, false. + /// + /// + /// if (request.Email.TryGetValue(out var email)) + /// { + /// requestBody["email"] = email; // email can be null + /// } + /// else + /// { + /// // Email is undefined - don't include in request + /// } + /// + /// + public bool TryGetValue(out T value) + { + if (_isDefined) + { + value = _value; + return true; + } + value = default!; + return false; + } + + /// + /// Implicitly converts a value to Optional<T>.Of(value). + /// This allows natural assignment: request.Name = "John" instead of request.Name = Optional<string?>.Of("John"). + /// + /// The value to convert (can be null if T is nullable). + public static implicit operator Optional(T value) => Of(value); + + /// + /// Returns a string representation of this Optional value. + /// + /// "Undefined" if not set, or "Defined(value)" if set. + public override string ToString() => _isDefined ? $"Defined({_value})" : "Undefined"; + + /// + /// Gets the boxed value. Returns null if undefined or if the value is null. + /// + public object? GetBoxedValue() + { + if (!_isDefined) + return null; + return _value; + } + + /// + public bool Equals(Optional other) => + _isDefined == other._isDefined && EqualityComparer.Default.Equals(_value, other._value); + + /// + public override bool Equals(object? obj) => obj is Optional other && Equals(other); + + /// + public override int GetHashCode() + { + if (!_isDefined) + return 0; + unchecked + { + int hash = 17; + hash = hash * 31 + 1; // _isDefined = true + hash = hash * 31 + (_value is null ? 0 : _value.GetHashCode()); + return hash; + } + } + + /// + /// Determines whether two Optional values are equal. + /// + /// The first Optional to compare. + /// The second Optional to compare. + /// True if the Optional values are equal; otherwise, false. + public static bool operator ==(Optional left, Optional right) => left.Equals(right); + + /// + /// Determines whether two Optional values are not equal. + /// + /// The first Optional to compare. + /// The second Optional to compare. + /// True if the Optional values are not equal; otherwise, false. + public static bool operator !=(Optional left, Optional right) => !left.Equals(right); +} + +/// +/// Extension methods for Optional<T> to simplify common operations. +/// +public static class OptionalExtensions +{ + /// + /// Adds the value to a dictionary if the optional is defined (even if the value is null). + /// This is useful for building JSON request payloads where null values should be included. + /// + /// The type of the optional value. + /// The optional value to add. + /// The dictionary to add to. + /// The key to use in the dictionary. + /// + /// + /// var dict = new Dictionary<string, object?>(); + /// request.Name.AddTo(dict, "name"); // Adds only if Name.IsDefined + /// request.Email.AddTo(dict, "email"); // Adds only if Email.IsDefined + /// + /// + public static void AddTo( + this Optional optional, + Dictionary dictionary, + string key + ) + { + if (optional.IsDefined) + { + dictionary[key] = optional.Value; + } + } + + /// + /// Executes an action if the optional is defined. + /// + /// The type of the optional value. + /// The optional value. + /// The action to execute with the value. + /// + /// + /// request.Name.IfDefined(name => Console.WriteLine($"Name: {name}")); + /// + /// + public static void IfDefined(this Optional optional, Action action) + { + if (optional.IsDefined) + { + action(optional.Value); + } + } + + /// + /// Maps the value to a new type if the optional is defined, otherwise returns undefined. + /// + /// The type of the original value. + /// The type to map to. + /// The optional value to map. + /// The mapping function. + /// An optional containing the mapped value if defined, otherwise undefined. + /// + /// + /// Optional<string?> name = Optional<string?>.Of("John"); + /// Optional<int> length = name.Map(n => n?.Length ?? 0); // Optional.Of(4) + /// + /// + public static Optional Map( + this Optional optional, + Func mapper + ) + { + return optional.IsDefined + ? Optional.Of(mapper(optional.Value)) + : Optional.Undefined; + } + + /// + /// Adds a nullable value to a dictionary only if it is not null. + /// This is useful for regular nullable properties where null means "omit from request". + /// + /// The type of the value (must be a reference type or Nullable<T>). + /// The nullable value to add. + /// The dictionary to add to. + /// The key to use in the dictionary. + /// + /// + /// var dict = new Dictionary<string, object?>(); + /// request.Description.AddIfNotNull(dict, "description"); // Only adds if not null + /// request.Score.AddIfNotNull(dict, "score"); // Only adds if not null + /// + /// + public static void AddIfNotNull( + this T? value, + Dictionary dictionary, + string key + ) + where T : class + { + if (value is not null) + { + dictionary[key] = value; + } + } + + /// + /// Adds a nullable value type to a dictionary only if it has a value. + /// This is useful for regular nullable properties where null means "omit from request". + /// + /// The underlying value type. + /// The nullable value to add. + /// The dictionary to add to. + /// The key to use in the dictionary. + /// + /// + /// var dict = new Dictionary<string, object?>(); + /// request.Age.AddIfNotNull(dict, "age"); // Only adds if HasValue + /// request.Score.AddIfNotNull(dict, "score"); // Only adds if HasValue + /// + /// + public static void AddIfNotNull( + this T? value, + Dictionary dictionary, + string key + ) + where T : struct + { + if (value.HasValue) + { + dictionary[key] = value.Value; + } + } +} + +/// +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. +/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. +/// +public class OptionalJsonConverterFactory : JsonConverterFactory +{ + public override bool CanConvert(global::System.Type typeToConvert) + { + if (!typeToConvert.IsGenericType) + return false; + + return typeToConvert.GetGenericTypeDefinition() == typeof(Optional<>); + } + + public override JsonConverter? CreateConverter( + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + var valueType = typeToConvert.GetGenericArguments()[0]; + var converterType = typeof(OptionalJsonConverter<>).MakeGenericType(valueType); + return (JsonConverter?)global::System.Activator.CreateInstance(converterType); + } +} + +/// +/// JSON converter for Optional<T> that unwraps the value during serialization. +/// The actual property skipping is handled by the OptionalTypeInfoResolver. +/// +public class OptionalJsonConverter : JsonConverter> +{ + public override Optional Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType == JsonTokenType.Null) + { + return Optional.Of(default!); + } + + var value = JsonSerializer.Deserialize(ref reader, options); + return Optional.Of(value!); + } + + public override void Write( + Utf8JsonWriter writer, + Optional value, + JsonSerializerOptions options + ) + { + // This will be called by the serializer + // We need to unwrap and serialize the inner value + // The TypeInfoResolver will handle skipping undefined values + + if (value.IsUndefined) + { + // This shouldn't be called for undefined values due to ShouldSerialize + // But if it is, write null and let the resolver filter it + writer.WriteNullValue(); + return; + } + + // Get the inner value + var innerValue = value.Value; + + // Write null directly if the value is null (don't use JsonSerializer.Serialize for null) + if (innerValue is null) + { + writer.WriteNullValue(); + return; + } + + // Serialize the unwrapped value + JsonSerializer.Serialize(writer, innerValue, options); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/OptionalAttribute.cs new file mode 100644 index 000000000000..00570d0f4680 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/OptionalAttribute.cs @@ -0,0 +1,17 @@ +namespace SeedCsharpXmlEntities.Core; + +/// +/// Marks a property as optional in the OpenAPI specification. +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). +/// +/// +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON +/// +/// Combine with [Nullable] to allow null values: +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) +/// +[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] +public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/AdditionalProperties.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/AdditionalProperties.cs new file mode 100644 index 000000000000..2f84deafb28b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/AdditionalProperties.cs @@ -0,0 +1,353 @@ +using global::System.Collections; +using global::System.Collections.ObjectModel; +using global::System.Text.Json; +using global::System.Text.Json.Nodes; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities; + +public record ReadOnlyAdditionalProperties : ReadOnlyAdditionalProperties +{ + internal ReadOnlyAdditionalProperties() { } + + internal ReadOnlyAdditionalProperties(IDictionary properties) + : base(properties) { } +} + +public record ReadOnlyAdditionalProperties : IReadOnlyDictionary +{ + private readonly Dictionary _extensionData = new(); + private readonly Dictionary _convertedCache = new(); + + internal ReadOnlyAdditionalProperties() + { + _extensionData = new Dictionary(); + _convertedCache = new Dictionary(); + } + + internal ReadOnlyAdditionalProperties(IDictionary properties) + { + _extensionData = new Dictionary(properties.Count); + _convertedCache = new Dictionary(properties.Count); + foreach (var kvp in properties) + { + if (kvp.Value is JsonElement element) + { + _extensionData.Add(kvp.Key, element); + } + else + { + _extensionData[kvp.Key] = JsonUtils.SerializeToElement(kvp.Value); + } + + _convertedCache[kvp.Key] = kvp.Value; + } + } + + private static T ConvertToT(JsonElement value) + { + if (typeof(T) == typeof(JsonElement)) + { + return (T)(object)value; + } + + return value.Deserialize(JsonOptions.JsonSerializerOptions)!; + } + + internal void CopyFromExtensionData(IDictionary extensionData) + { + _extensionData.Clear(); + _convertedCache.Clear(); + foreach (var kvp in extensionData) + { + _extensionData[kvp.Key] = kvp.Value; + if (kvp.Value is T value) + { + _convertedCache[kvp.Key] = value; + } + } + } + + private T GetCached(string key) + { + if (_convertedCache.TryGetValue(key, out var cached)) + { + return cached; + } + + var value = ConvertToT(_extensionData[key]); + _convertedCache[key] = value; + return value; + } + + public IEnumerator> GetEnumerator() + { + return _extensionData + .Select(kvp => new KeyValuePair(kvp.Key, GetCached(kvp.Key))) + .GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public int Count => _extensionData.Count; + + public bool ContainsKey(string key) => _extensionData.ContainsKey(key); + + public bool TryGetValue(string key, out T value) + { + if (_convertedCache.TryGetValue(key, out value!)) + { + return true; + } + + if (_extensionData.TryGetValue(key, out var element)) + { + value = ConvertToT(element); + _convertedCache[key] = value; + return true; + } + + return false; + } + + public T this[string key] => GetCached(key); + + public IEnumerable Keys => _extensionData.Keys; + + public IEnumerable Values => Keys.Select(GetCached); +} + +public record AdditionalProperties : AdditionalProperties +{ + public AdditionalProperties() { } + + public AdditionalProperties(IDictionary properties) + : base(properties) { } +} + +public record AdditionalProperties : IDictionary +{ + private readonly Dictionary _extensionData; + private readonly Dictionary _convertedCache; + + public AdditionalProperties() + { + _extensionData = new Dictionary(); + _convertedCache = new Dictionary(); + } + + public AdditionalProperties(IDictionary properties) + { + _extensionData = new Dictionary(properties.Count); + _convertedCache = new Dictionary(properties.Count); + foreach (var kvp in properties) + { + _extensionData[kvp.Key] = kvp.Value; + _convertedCache[kvp.Key] = kvp.Value; + } + } + + private static T ConvertToT(object? extensionDataValue) + { + return extensionDataValue switch + { + T value => value, + JsonElement jsonElement => jsonElement.Deserialize( + JsonOptions.JsonSerializerOptions + )!, + JsonNode jsonNode => jsonNode.Deserialize(JsonOptions.JsonSerializerOptions)!, + _ => JsonUtils + .SerializeToElement(extensionDataValue) + .Deserialize(JsonOptions.JsonSerializerOptions)!, + }; + } + + internal void CopyFromExtensionData(IDictionary extensionData) + { + _extensionData.Clear(); + _convertedCache.Clear(); + foreach (var kvp in extensionData) + { + _extensionData[kvp.Key] = kvp.Value; + if (kvp.Value is T value) + { + _convertedCache[kvp.Key] = value; + } + } + } + + internal void CopyToExtensionData(IDictionary extensionData) + { + extensionData.Clear(); + foreach (var kvp in _extensionData) + { + extensionData[kvp.Key] = kvp.Value; + } + } + + public JsonObject ToJsonObject() => + ( + JsonUtils.SerializeToNode(_extensionData) + ?? throw new InvalidOperationException( + "Failed to serialize AdditionalProperties to JSON Node." + ) + ).AsObject(); + + public JsonNode ToJsonNode() => + JsonUtils.SerializeToNode(_extensionData) + ?? throw new InvalidOperationException( + "Failed to serialize AdditionalProperties to JSON Node." + ); + + public JsonElement ToJsonElement() => JsonUtils.SerializeToElement(_extensionData); + + public JsonDocument ToJsonDocument() => JsonUtils.SerializeToDocument(_extensionData); + + public IReadOnlyDictionary ToJsonElementDictionary() + { + return new ReadOnlyDictionary( + _extensionData.ToDictionary( + kvp => kvp.Key, + kvp => + { + if (kvp.Value is JsonElement jsonElement) + { + return jsonElement; + } + + return JsonUtils.SerializeToElement(kvp.Value); + } + ) + ); + } + + public ICollection Keys => _extensionData.Keys; + + public ICollection Values + { + get + { + var values = new T[_extensionData.Count]; + var i = 0; + foreach (var key in Keys) + { + values[i++] = GetCached(key); + } + + return values; + } + } + + private T GetCached(string key) + { + if (_convertedCache.TryGetValue(key, out var value)) + { + return value; + } + + value = ConvertToT(_extensionData[key]); + _convertedCache.Add(key, value); + return value; + } + + private void SetCached(string key, T value) + { + _extensionData[key] = value; + _convertedCache[key] = value; + } + + private void AddCached(string key, T value) + { + _extensionData.Add(key, value); + _convertedCache.Add(key, value); + } + + private bool RemoveCached(string key) + { + var isRemoved = _extensionData.Remove(key); + _convertedCache.Remove(key); + return isRemoved; + } + + public int Count => _extensionData.Count; + public bool IsReadOnly => false; + + public T this[string key] + { + get => GetCached(key); + set => SetCached(key, value); + } + + public void Add(string key, T value) => AddCached(key, value); + + public void Add(KeyValuePair item) => AddCached(item.Key, item.Value); + + public bool Remove(string key) => RemoveCached(key); + + public bool Remove(KeyValuePair item) => RemoveCached(item.Key); + + public bool ContainsKey(string key) => _extensionData.ContainsKey(key); + + public bool Contains(KeyValuePair item) + { + return _extensionData.ContainsKey(item.Key) + && EqualityComparer.Default.Equals(GetCached(item.Key), item.Value); + } + + public bool TryGetValue(string key, out T value) + { + if (_convertedCache.TryGetValue(key, out value!)) + { + return true; + } + + if (_extensionData.TryGetValue(key, out var extensionDataValue)) + { + value = ConvertToT(extensionDataValue); + _convertedCache[key] = value; + return true; + } + + return false; + } + + public void Clear() + { + _extensionData.Clear(); + _convertedCache.Clear(); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + if (array is null) + { + throw new ArgumentNullException(nameof(array)); + } + + if (arrayIndex < 0 || arrayIndex > array.Length) + { + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + } + + if (array.Length - arrayIndex < _extensionData.Count) + { + throw new ArgumentException( + "The array does not have enough space to copy the elements." + ); + } + + foreach (var kvp in _extensionData) + { + array[arrayIndex++] = new KeyValuePair(kvp.Key, GetCached(kvp.Key)); + } + } + + public IEnumerator> GetEnumerator() + { + return _extensionData + .Select(kvp => new KeyValuePair(kvp.Key, GetCached(kvp.Key))) + .GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/ClientOptions.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/ClientOptions.cs new file mode 100644 index 000000000000..d00874461f3c --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/ClientOptions.cs @@ -0,0 +1,84 @@ +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities; + +[Serializable] +public partial class ClientOptions +{ + /// + /// The http headers sent with the request. + /// + internal Headers Headers { get; init; } = new(); + + /// + /// The Base URL for the API. + /// + public string BaseUrl { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = ""; + + /// + /// The http client used to make requests. + /// + public HttpClient HttpClient { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = DefaultHttpClientFactory.Create(); + + /// + /// Additional headers to be sent with HTTP requests. + /// Headers with matching keys will be overwritten by headers set on the request. + /// + public IEnumerable> AdditionalHeaders { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = []; + + /// + /// The max number of retries to attempt. + /// + public int MaxRetries { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = 2; + + /// + /// The timeout for the request. + /// + public TimeSpan Timeout { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = TimeSpan.FromMilliseconds(30000); + + /// + /// Clones this and returns a new instance + /// + internal ClientOptions Clone() + { + return new ClientOptions + { + BaseUrl = BaseUrl, + HttpClient = HttpClient, + MaxRetries = MaxRetries, + Timeout = Timeout, + Headers = new Headers(new Dictionary(Headers)), + AdditionalHeaders = AdditionalHeaders, + }; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/FileParameter.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/FileParameter.cs new file mode 100644 index 000000000000..a6c1154b282b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/FileParameter.cs @@ -0,0 +1,63 @@ +namespace SeedCsharpXmlEntities; + +/// +/// File parameter for uploading files. +/// +public record FileParameter : IDisposable +#if NET6_0_OR_GREATER + , IAsyncDisposable +#endif +{ + private bool _disposed; + + /// + /// The name of the file to be uploaded. + /// + public string? FileName { get; set; } + + /// + /// The content type of the file to be uploaded. + /// + public string? ContentType { get; set; } + + /// + /// The content of the file to be uploaded. + /// + public required Stream Stream { get; set; } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + if (disposing) + { + Stream.Dispose(); + } + + _disposed = true; + } + +#if NET6_0_OR_GREATER + /// + public async ValueTask DisposeAsync() + { + if (!_disposed) + { + await Stream.DisposeAsync().ConfigureAwait(false); + _disposed = true; + } + + GC.SuppressFinalize(this); + } +#endif + + public static implicit operator FileParameter(Stream stream) => new() { Stream = stream }; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/RawResponse.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/RawResponse.cs new file mode 100644 index 000000000000..52f1bd97d565 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/RawResponse.cs @@ -0,0 +1,24 @@ +using global::System.Net; + +namespace SeedCsharpXmlEntities; + +/// +/// Contains HTTP response metadata including status code, URL, and headers. +/// +public record RawResponse +{ + /// + /// The HTTP status code of the response. + /// + public required HttpStatusCode StatusCode { get; init; } + + /// + /// The request URL that generated this response. + /// + public required Uri Url { get; init; } + + /// + /// The HTTP response headers. + /// + public required Core.ResponseHeaders Headers { get; init; } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/RequestOptions.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/RequestOptions.cs new file mode 100644 index 000000000000..1d63eb845e2d --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/RequestOptions.cs @@ -0,0 +1,86 @@ +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities; + +[Serializable] +public partial class RequestOptions : IRequestOptions +{ + /// + /// The Base URL for the API. + /// + public string? BaseUrl { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// The http client used to make requests. + /// + public HttpClient? HttpClient { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// Additional headers to be sent with the request. + /// Headers previously set with matching keys will be overwritten. + /// + public IEnumerable> AdditionalHeaders { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = []; + + /// + /// The max number of retries to attempt. + /// + public int? MaxRetries { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// The timeout for the request. + /// + public TimeSpan? Timeout { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } + + /// + /// Additional query parameters sent with the request. + /// + public IEnumerable> AdditionalQueryParameters { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = Enumerable.Empty>(); + + /// + /// Additional body properties sent with the request. + /// This is only applied to JSON requests. + /// + public object? AdditionalBodyProperties { get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesApiException.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesApiException.cs new file mode 100644 index 000000000000..3f814522c310 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesApiException.cs @@ -0,0 +1,28 @@ +namespace SeedCsharpXmlEntities; + +/// +/// This exception type will be thrown for any non-2XX API responses. +/// +public class SeedCsharpXmlEntitiesApiException( + string message, + int statusCode, + object body, + Exception? innerException = null, + SeedCsharpXmlEntities.RawResponse? rawResponse = null +) : SeedCsharpXmlEntitiesException(message, innerException) +{ + /// + /// The error code of the response that triggered the exception. + /// + public int StatusCode => statusCode; + + /// + /// The body of the response that triggered the exception. + /// + public object Body => body; + + /// + /// The raw HTTP response (status code, URL, headers) that triggered the exception, if available. + /// + public SeedCsharpXmlEntities.RawResponse? RawResponse => rawResponse; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesException.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesException.cs new file mode 100644 index 000000000000..6801d0fab3c5 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/SeedCsharpXmlEntitiesException.cs @@ -0,0 +1,7 @@ +namespace SeedCsharpXmlEntities; + +/// +/// Base exception class for all exceptions thrown by the SDK. +/// +public class SeedCsharpXmlEntitiesException(string message, Exception? innerException = null) + : Exception(message, innerException); diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/Version.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/Version.cs new file mode 100644 index 000000000000..00b2fffd7856 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/Version.cs @@ -0,0 +1,7 @@ +namespace SeedCsharpXmlEntities; + +[Serializable] +internal class Version +{ + public const string Current = "0.0.1"; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/WithRawResponse.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/WithRawResponse.cs new file mode 100644 index 000000000000..b3a34aeaa71f --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/WithRawResponse.cs @@ -0,0 +1,18 @@ +namespace SeedCsharpXmlEntities; + +/// +/// Wraps a parsed response value with its raw HTTP response metadata. +/// +/// The type of the parsed response data. +public readonly struct WithRawResponse +{ + /// + /// The parsed response data. + /// + public required T Data { get; init; } + + /// + /// The raw HTTP response metadata. + /// + public required RawResponse RawResponse { get; init; } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseStream.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseStream.cs new file mode 100644 index 000000000000..45e8188e2b17 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseStream.cs @@ -0,0 +1,66 @@ +using global::System.Collections.Generic; +using global::System.Runtime.CompilerServices; +using global::System.Threading; +using global::System.Threading.Tasks; + +namespace SeedCsharpXmlEntities; + +/// +/// A streaming wrapper that provides dual-mode access to a streaming endpoint: +/// - Direct await foreach iterates the parsed stream values (zero-allocation path for common case) +/// - .WithRawResponse() yields the underlying exposing both the stream and raw response metadata +/// +/// The element type of the parsed stream. +public readonly struct WithRawResponseStream : IAsyncEnumerable +{ + private readonly Task>> _task; + private readonly CancellationToken _originalCancellationToken; + + /// + /// Creates a new WithRawResponseStream wrapping the given task that opens the underlying HTTP response. + /// + /// The task opening the HTTP response and producing the parsed stream. + /// + /// The cancellation token supplied at the SDK call site. Linked with any token supplied via + /// .WithCancellation(...) on the enumerator so both cancel the inner reads. + /// + public WithRawResponseStream( + Task>> task, + CancellationToken cancellationToken = default + ) + { + _task = task; + _originalCancellationToken = cancellationToken; + } + + /// + /// Returns the underlying task that yields both the stream and raw response metadata once headers are received. + /// + public Task>> WithRawResponse() => _task; + + /// + /// Returns an enumerator that iterates the parsed stream values. Awaits the underlying HTTP response, then yields each parsed element from the body stream. + /// + public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) => + EnumerateAsync(_task, _originalCancellationToken, cancellationToken) + .GetAsyncEnumerator(cancellationToken); + + private static async IAsyncEnumerable EnumerateAsync( + Task>> task, + CancellationToken originalCancellationToken, + [EnumeratorCancellation] CancellationToken cancellationToken + ) + { + using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource( + originalCancellationToken, + cancellationToken + ); + var wrapped = await task.ConfigureAwait(false); + await foreach ( + var item in wrapped.Data.WithCancellation(linkedCts.Token).ConfigureAwait(false) + ) + { + yield return item; + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseTask.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseTask.cs new file mode 100644 index 000000000000..21cfc200c565 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/Public/WithRawResponseTask.cs @@ -0,0 +1,187 @@ +using global::System.Runtime.CompilerServices; + +namespace SeedCsharpXmlEntities; + +/// +/// A task-like type that wraps Task<WithRawResponse<T>> and provides dual-mode awaiting: +/// - Direct await yields just T (zero-allocation path for common case) +/// - .WithRawResponse() yields WithRawResponse<T> (when raw response metadata is needed) +/// +/// The type of the parsed response data. +public readonly struct WithRawResponseTask +{ + private readonly global::System.Threading.Tasks.Task> _task; + + /// + /// Creates a new WithRawResponseTask wrapping the given task. + /// + public WithRawResponseTask(global::System.Threading.Tasks.Task> task) + { + _task = task; + } + + /// + /// Returns the underlying task that yields both the data and raw response metadata. + /// + public global::System.Threading.Tasks.Task> WithRawResponse() => _task; + + /// + /// Gets the custom awaiter that unwraps to just T when awaited. + /// + public Awaiter GetAwaiter() => new(_task.GetAwaiter()); + + /// + /// Configures the awaiter to continue on the captured context or not. + /// + public ConfiguredTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) => + new(_task.ConfigureAwait(continueOnCapturedContext)); + + /// + /// Implicitly converts WithRawResponseTask<T> to global::System.Threading.Tasks.Task<T> for backward compatibility. + /// The resulting task will yield just the data when awaited. + /// + public static implicit operator global::System.Threading.Tasks.Task( + WithRawResponseTask task + ) + { + return task._task.ContinueWith( + t => t.Result.Data, + TaskContinuationOptions.ExecuteSynchronously + ); + } + + /// + /// Custom awaiter that unwraps WithRawResponse<T> to just T. + /// + public readonly struct Awaiter : ICriticalNotifyCompletion + { + private readonly TaskAwaiter> _awaiter; + + internal Awaiter(TaskAwaiter> awaiter) + { + _awaiter = awaiter; + } + + /// + /// Gets whether the underlying task has completed. + /// + public bool IsCompleted => _awaiter.IsCompleted; + + /// + /// Gets the result, unwrapping to just the data. + /// + public T GetResult() => _awaiter.GetResult().Data; + + /// + /// Schedules the continuation action. + /// + public void OnCompleted(global::System.Action continuation) => + _awaiter.OnCompleted(continuation); + + /// + /// Schedules the continuation action without capturing the execution context. + /// + public void UnsafeOnCompleted(global::System.Action continuation) => + _awaiter.UnsafeOnCompleted(continuation); + } + + /// + /// Awaitable type returned by ConfigureAwait that unwraps to just T. + /// + public readonly struct ConfiguredTaskAwaitable + { + private readonly ConfiguredTaskAwaitable> _configuredTask; + + internal ConfiguredTaskAwaitable(ConfiguredTaskAwaitable> configuredTask) + { + _configuredTask = configuredTask; + } + + /// + /// Gets the configured awaiter that unwraps to just T. + /// + public ConfiguredAwaiter GetAwaiter() => new(_configuredTask.GetAwaiter()); + + /// + /// Custom configured awaiter that unwraps WithRawResponse<T> to just T. + /// + public readonly struct ConfiguredAwaiter : ICriticalNotifyCompletion + { + private readonly ConfiguredTaskAwaitable< + WithRawResponse + >.ConfiguredTaskAwaiter _awaiter; + + internal ConfiguredAwaiter( + ConfiguredTaskAwaitable>.ConfiguredTaskAwaiter awaiter + ) + { + _awaiter = awaiter; + } + + /// + /// Gets whether the underlying task has completed. + /// + public bool IsCompleted => _awaiter.IsCompleted; + + /// + /// Gets the result, unwrapping to just the data. + /// + public T GetResult() => _awaiter.GetResult().Data; + + /// + /// Schedules the continuation action. + /// + public void OnCompleted(global::System.Action continuation) => + _awaiter.OnCompleted(continuation); + + /// + /// Schedules the continuation action without capturing the execution context. + /// + public void UnsafeOnCompleted(global::System.Action continuation) => + _awaiter.UnsafeOnCompleted(continuation); + } + } +} + +/// +/// A task-like type that wraps Task<RawResponse> and provides dual-mode awaiting for endpoints with no response body: +/// - Direct await completes with no value (void semantics) +/// - .WithRawResponse() yields RawResponse (when raw response metadata is needed) +/// +public readonly struct WithRawResponseTask +{ + private readonly global::System.Threading.Tasks.Task _task; + + /// + /// Creates a new WithRawResponseTask wrapping the given task. + /// + public WithRawResponseTask(global::System.Threading.Tasks.Task task) + { + _task = task; + } + + /// + /// Returns the underlying task that yields raw response metadata. + /// + public global::System.Threading.Tasks.Task WithRawResponse() => _task; + + /// + /// Awaiter delegates to the non-generic Task, completing with no value. + /// + public TaskAwaiter GetAwaiter() => ((global::System.Threading.Tasks.Task)_task).GetAwaiter(); + + /// + /// Configures the awaiter to continue on the captured context or not. The configured awaitable completes with no value. + /// + public global::System.Runtime.CompilerServices.ConfiguredTaskAwaitable ConfigureAwait( + bool continueOnCapturedContext + ) => ((global::System.Threading.Tasks.Task)_task).ConfigureAwait(continueOnCapturedContext); + + /// + /// Implicitly converts WithRawResponseTask to global::System.Threading.Tasks.Task for backward compatibility. + /// + public static implicit operator global::System.Threading.Tasks.Task(WithRawResponseTask task) + { + return task._task; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/QueryStringBuilder.cs new file mode 100644 index 000000000000..1bd6d3fb9c78 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/QueryStringBuilder.cs @@ -0,0 +1,656 @@ +using global::System.Buffers; +using global::System.Runtime.CompilerServices; +#if !NET6_0_OR_GREATER +using global::System.Text; +#endif + +namespace SeedCsharpXmlEntities.Core; + +/// +/// High-performance query string builder with RFC 3986 compliant percent-encoding. +/// Uses span-based APIs on .NET 6+ and StringBuilder fallback for older targets. +/// +/// RFC 3986 defines the following relevant productions: +/// pchar = unreserved / pct-encoded / sub-delims / ":" / "@" +/// query = *( pchar / "/" / "?" ) +/// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" +/// sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" +/// +/// Three encoding contexts are distinguished: +/// Path segment (pchar): unreserved + sub-delims + ":" + "@" +/// Query key: query chars minus "&", "=", "+", ";", "#" +/// Query value: query chars minus "&", "+", ";", "#" +/// +/// ";" is percent-encoded in queries even though RFC 3986 permits it: it is a +/// legacy parameter separator that many servers and frameworks still split on, +/// so leaving it raw truncates the value. +/// +internal static class QueryStringBuilder +{ + // ────────────────────────────────────────────────────────────────────── + // RFC 3986 character sets + // + // Query key safe: unreserved + (sub-delims \ {& = + ;}) + : @ / ? + // Query value safe: unreserved + (sub-delims \ {& + ;}) + : @ / ? + // Path segment safe: unreserved + sub-delims + : @ + // ────────────────────────────────────────────────────────────────────── + +#if NET8_0_OR_GREATER + private static readonly SearchValues SafeQueryKeyChars = SearchValues.Create( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!$'()*,:@/?" + ); + + private static readonly SearchValues SafeQueryValueChars = SearchValues.Create( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!$'()*,=:@/?" + ); + + private static readonly SearchValues SafePathChars = SearchValues.Create( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!$&'()*+,;=:@" + ); +#else + private const string SafeQueryKeyChars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!$'()*,:@/?"; + + private const string SafeQueryValueChars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!$'()*,=:@/?"; + + private const string SafePathChars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!$&'()*+,;=:@"; +#endif + +#if NET7_0_OR_GREATER + private static ReadOnlySpan UpperHexChars => "0123456789ABCDEF"u8; +#else + private static readonly byte[] UpperHexChars = + { + (byte)'0', + (byte)'1', + (byte)'2', + (byte)'3', + (byte)'4', + (byte)'5', + (byte)'6', + (byte)'7', + (byte)'8', + (byte)'9', + (byte)'A', + (byte)'B', + (byte)'C', + (byte)'D', + (byte)'E', + (byte)'F', + }; +#endif + + private enum EncodingContext + { + QueryKey, + QueryValue, + Path, + } + + /// + /// Percent-encodes a path segment value per RFC 3986 section 3.3 (pchar). + /// Allowed unencoded: unreserved / sub-delims / ":" / "@" + /// + public static string EncodePathSegment(string value) + { + if (string.IsNullOrEmpty(value)) + return value; + +#if NET6_0_OR_GREATER + if (!NeedsEncoding(value.AsSpan(), EncodingContext.Path)) + return value; + + var buffer = ArrayPool.Shared.Rent(value.Length * 3); + try + { + var written = EncodeSlow(value.AsSpan(), buffer.AsSpan(), EncodingContext.Path); + return new string(buffer.AsSpan(0, written)); + } + finally + { + ArrayPool.Shared.Return(buffer); + } +#else + var sb = new StringBuilder(value.Length); + AppendEncoded(sb, value, EncodingContext.Path); + return sb.ToString(); +#endif + } + +#if NET6_0_OR_GREATER + /// + /// Builds a query string from the provided parameters. + /// + public static string Build(ReadOnlySpan> parameters) + { + if (parameters.IsEmpty) + return string.Empty; + + var estimatedLength = EstimateLength(parameters); + if (estimatedLength == 0) + return string.Empty; + + var bufferSize = Math.Min(estimatedLength * 3, 8192); + var buffer = ArrayPool.Shared.Rent(bufferSize); + + try + { + var written = BuildCore(parameters, buffer); + return new string(buffer.AsSpan(0, written)); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + + private static int EstimateLength(ReadOnlySpan> parameters) + { + var estimatedLength = 0; + foreach (var kvp in parameters) + { + estimatedLength += kvp.Key.Length + kvp.Value.Length + 2; + } + return estimatedLength; + } +#endif + + /// + /// Builds a query string from the provided parameters. + /// + public static string Build(IEnumerable> parameters) + { +#if NET6_0_OR_GREATER + // Try to get span access for collections that support it + if (parameters is ICollection> collection) + { + if (collection.Count == 0) + return string.Empty; + + var array = ArrayPool>.Shared.Rent(collection.Count); + try + { + collection.CopyTo(array, 0); + return Build(array.AsSpan(0, collection.Count)); + } + finally + { + ArrayPool>.Shared.Return(array); + } + } + + // Fallback for non-collection enumerables + using var enumerator = parameters.GetEnumerator(); + if (!enumerator.MoveNext()) + return string.Empty; + + var buffer = ArrayPool.Shared.Rent(4096); + try + { + var position = 0; + var first = true; + + do + { + var kvp = enumerator.Current; + + // Ensure capacity (worst case: 3x for encoding + separators) + var required = (kvp.Key.Length + kvp.Value.Length + 2) * 3; + if (position + required > buffer.Length) + { + var newBuffer = ArrayPool.Shared.Rent(buffer.Length * 2); + buffer.AsSpan(0, position).CopyTo(newBuffer); + ArrayPool.Shared.Return(buffer); + buffer = newBuffer; + } + + buffer[position++] = first ? '?' : '&'; + first = false; + + position += EncodeWithCharSet( + kvp.Key.AsSpan(), + buffer.AsSpan(position), + EncodingContext.QueryKey + ); + buffer[position++] = '='; + position += EncodeWithCharSet( + kvp.Value.AsSpan(), + buffer.AsSpan(position), + EncodingContext.QueryValue + ); + } while (enumerator.MoveNext()); + + return first ? string.Empty : new string(buffer.AsSpan(0, position)); + } + finally + { + ArrayPool.Shared.Return(buffer); + } +#else + // netstandard2.0 / net462 fallback using StringBuilder + var sb = new StringBuilder(); + var first = true; + + foreach (var kvp in parameters) + { + sb.Append(first ? '?' : '&'); + first = false; + + AppendEncoded(sb, kvp.Key, EncodingContext.QueryKey); + sb.Append('='); + AppendEncoded(sb, kvp.Value, EncodingContext.QueryValue); + } + + return sb.ToString(); +#endif + } + +#if NET6_0_OR_GREATER + private static int BuildCore( + ReadOnlySpan> parameters, + Span buffer + ) + { + var position = 0; + var first = true; + + foreach (var kvp in parameters) + { + buffer[position++] = first ? '?' : '&'; + first = false; + + position += EncodeWithCharSet( + kvp.Key.AsSpan(), + buffer.Slice(position), + EncodingContext.QueryKey + ); + buffer[position++] = '='; + position += EncodeWithCharSet( + kvp.Value.AsSpan(), + buffer.Slice(position), + EncodingContext.QueryValue + ); + } + + return position; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int EncodeWithCharSet( + ReadOnlySpan input, + Span output, + EncodingContext context + ) + { + if (!NeedsEncoding(input, context)) + { + input.CopyTo(output); + return input.Length; + } + + return EncodeSlow(input, output, context); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool NeedsEncoding(ReadOnlySpan value, EncodingContext context) + { + return context switch + { + EncodingContext.QueryKey => value.ContainsAnyExcept(SafeQueryKeyChars), + EncodingContext.QueryValue => value.ContainsAnyExcept(SafeQueryValueChars), + EncodingContext.Path => value.ContainsAnyExcept(SafePathChars), + _ => true, + }; + } + + private static int EncodeSlow( + ReadOnlySpan input, + Span output, + EncodingContext context + ) + { + var position = 0; + + foreach (var c in input) + { + if (IsSafeChar(c, context)) + { + output[position++] = c; + } + else if (c == ' ') + { + output[position++] = '%'; + output[position++] = '2'; + output[position++] = '0'; + } + else if (char.IsAscii(c)) + { + position += EncodeAscii((byte)c, output.Slice(position)); + } + else + { + position += EncodeUtf8(c, output.Slice(position)); + } + } + + return position; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int EncodeAscii(byte value, Span output) + { + output[0] = '%'; + output[1] = (char)UpperHexChars[value >> 4]; + output[2] = (char)UpperHexChars[value & 0xF]; + return 3; + } + + private static int EncodeUtf8(char c, Span output) + { + Span utf8Bytes = stackalloc byte[4]; + Span singleChar = stackalloc char[1] { c }; + var byteCount = global::System.Text.Encoding.UTF8.GetBytes(singleChar, utf8Bytes); + + var position = 0; + for (var i = 0; i < byteCount; i++) + { + output[position++] = '%'; + output[position++] = (char)UpperHexChars[utf8Bytes[i] >> 4]; + output[position++] = (char)UpperHexChars[utf8Bytes[i] & 0xF]; + } + + return position; + } +#else + // netstandard2.0 / net462 StringBuilder-based encoding + private static void AppendEncoded(StringBuilder sb, string value, EncodingContext context) + { + foreach (var c in value) + { + if (IsSafeChar(c, context)) + { + sb.Append(c); + } + else if (c == ' ') + { + sb.Append("%20"); + } + else if (c <= 127) + { + AppendPercentEncoded(sb, (byte)c); + } + else + { + var bytes = Encoding.UTF8.GetBytes(new[] { c }); + foreach (var b in bytes) + { + AppendPercentEncoded(sb, b); + } + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AppendPercentEncoded(StringBuilder sb, byte value) + { + sb.Append('%'); + sb.Append((char)UpperHexChars[value >> 4]); + sb.Append((char)UpperHexChars[value & 0xF]); + } +#endif + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsSafeChar(char c, EncodingContext context) + { + return context switch + { + EncodingContext.QueryKey => IsSafeQueryKeyChar(c), + EncodingContext.QueryValue => IsSafeQueryValueChar(c), + EncodingContext.Path => IsSafePathChar(c), + _ => false, + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsSafeQueryKeyChar(char c) + { +#if NET8_0_OR_GREATER + return SafeQueryKeyChars.Contains(c); +#else + // query = *( pchar / "/" / "?" ) minus "&", "=", "+", ";", "#" + return (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z') + || (c >= '0' && c <= '9') + || c == '-' + || c == '_' + || c == '.' + || c == '~' + || c == '!' + || c == '$' + || c == (char)39 // single quote + || c == '(' + || c == ')' + || c == '*' + || c == ',' + || c == ':' + || c == '@' + || c == '/' + || c == '?'; +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsSafeQueryValueChar(char c) + { +#if NET8_0_OR_GREATER + return SafeQueryValueChars.Contains(c); +#else + // query = *( pchar / "/" / "?" ) minus "&", "+", ";", "#" + return (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z') + || (c >= '0' && c <= '9') + || c == '-' + || c == '_' + || c == '.' + || c == '~' + || c == '!' + || c == '$' + || c == (char)39 // single quote + || c == '(' + || c == ')' + || c == '*' + || c == ',' + || c == '=' + || c == ':' + || c == '@' + || c == '/' + || c == '?'; +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsSafePathChar(char c) + { +#if NET8_0_OR_GREATER + return SafePathChars.Contains(c); +#else + // pchar = unreserved / sub-delims / ":" / "@" + return (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z') + || (c >= '0' && c <= '9') + || c == '-' + || c == '_' + || c == '.' + || c == '~' + || c == '!' + || c == '$' + || c == '&' + || c == (char)39 // single quote + || c == '(' + || c == ')' + || c == '*' + || c == '+' + || c == ',' + || c == ';' + || c == '=' + || c == ':' + || c == '@'; +#endif + } + + /// + /// Fluent builder for constructing query strings with support for simple parameters and deep object notation. + /// + public sealed class Builder + { + private readonly List> _params; + + /// + /// Initializes a new instance with default capacity. + /// + public Builder() + { + _params = new List>(); + } + + /// + /// Initializes a new instance with the specified initial capacity. + /// + public Builder(int capacity) + { + _params = new List>(capacity); + } + + /// + /// Adds a simple parameter. For collections, adds multiple key-value pairs (one per element). + /// + public Builder Add(string key, object? value) + { + if (value is null) + { + return this; + } + + // Handle string separately since it implements IEnumerable + if (value is string stringValue) + { + _params.Add(new KeyValuePair(key, stringValue)); + return this; + } + + // Handle collections (arrays, lists, etc.) - add each element as a separate key-value pair + if ( + value + is global::System.Collections.IEnumerable enumerable + and not global::System.Collections.IDictionary + ) + { + foreach (var item in enumerable) + { + if (item is not null) + { + _params.Add( + new KeyValuePair( + key, + ValueConvert.ToQueryStringValue(item) + ) + ); + } + } + return this; + } + + // Handle scalar values + _params.Add( + new KeyValuePair(key, ValueConvert.ToQueryStringValue(value)) + ); + return this; + } + + /// + /// Sets a parameter, removing any existing parameters with the same key before adding the new value. + /// For collections, removes all existing parameters with the key, then adds multiple key-value pairs (one per element). + /// This allows overriding parameters set earlier in the builder. + /// + public Builder Set(string key, object? value) + { + // Remove all existing parameters with this key + _params.RemoveAll(kv => kv.Key == key); + + // Add the new value(s) + return Add(key, value); + } + + /// + /// Merges additional query parameters with override semantics. + /// Groups parameters by key and calls Set() once per unique key. + /// This ensures that parameters with the same key are properly merged: + /// - If a key appears once, it's added as a single value + /// - If a key appears multiple times, all values are added as an array + /// - All parameters override any existing parameters with the same key + /// + public Builder MergeAdditional( + global::System.Collections.Generic.IEnumerable>? additionalParameters + ) + { + if (additionalParameters is null) + { + return this; + } + + // Group by key to handle multiple values for the same key correctly + var grouped = additionalParameters + .GroupBy(kv => kv.Key) + .Select(g => new global::System.Collections.Generic.KeyValuePair( + g.Key, + g.Count() == 1 ? (object)g.First().Value : g.Select(kv => kv.Value).ToArray() + )); + + foreach (var param in grouped) + { + Set(param.Key, param.Value); + } + + return this; + } + + /// + /// Adds a complex object using deep object notation with a prefix. + /// Deep object notation nests properties with brackets: prefix[key][nested]=value + /// + public Builder AddDeepObject(string prefix, object? value) + { + if (value is not null) + { + _params.AddRange(QueryStringConverter.ToDeepObject(prefix, value)); + } + return this; + } + + /// + /// Adds a complex object using exploded form notation with an optional prefix. + /// Exploded form flattens properties: prefix[key]=value (no deep nesting). + /// + public Builder AddExploded(string prefix, object? value) + { + if (value is not null) + { + _params.AddRange(QueryStringConverter.ToExplodedForm(prefix, value)); + } + return this; + } + + /// + /// Builds the final query string. + /// + public string Build() + { + return QueryStringBuilder.Build(_params); + } + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/QueryStringConverter.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/QueryStringConverter.cs new file mode 100644 index 000000000000..430cc9ad36c1 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/QueryStringConverter.cs @@ -0,0 +1,259 @@ +using global::System.Text.Json; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Converts an object into a query string collection. +/// +internal static class QueryStringConverter +{ + /// + /// Converts an object into a query string collection using Deep Object notation with a prefix. + /// + /// The prefix to prepend to all keys (e.g., "session_settings"). Pass empty string for no prefix. + /// Object to form URL-encode. Can be an object, array of objects, or dictionary. + /// Throws when passing in a string or primitive value. + /// A collection of key value pairs. The keys and values are not URL encoded. + internal static IEnumerable> ToDeepObject( + string prefix, + object value + ) + { + var queryCollection = new List>(); + var json = JsonUtils.SerializeToElement(value); + JsonToDeepObject(json, prefix, queryCollection); + return queryCollection; + } + + /// + /// Converts an object into a query string collection using Deep Object notation. + /// + /// Object to form URL-encode. Can be an object, array of objects, or dictionary. + /// Throws when passing in a string or primitive value. + /// A collection of key value pairs. The keys and values are not URL encoded. + internal static IEnumerable> ToDeepObject(object value) + { + return ToDeepObject("", value); + } + + /// + /// Converts an object into a query string collection using Exploded Form notation with a prefix. + /// + /// The prefix to prepend to all keys. Pass empty string for no prefix. + /// Object to form URL-encode. You can pass in an object or dictionary, but not lists, strings, or primitives. + /// Throws when passing in a list, a string, or a primitive value. + /// A collection of key value pairs. The keys and values are not URL encoded. + internal static IEnumerable> ToExplodedForm( + string prefix, + object value + ) + { + var queryCollection = new List>(); + var json = JsonUtils.SerializeToElement(value); + AssertRootJson(json); + JsonToFormExploded(json, prefix, queryCollection); + return queryCollection; + } + + /// + /// Converts an object into a query string collection using Exploded Form notation. + /// + /// Object to form URL-encode. You can pass in an object or dictionary, but not lists, strings, or primitives. + /// Throws when passing in a list, a string, or a primitive value. + /// A collection of key value pairs. The keys and values are not URL encoded. + internal static IEnumerable> ToExplodedForm(object value) + { + return ToExplodedForm("", value); + } + + /// + /// Converts an object into a query string collection using Form notation without exploding parameters. + /// + /// Object to form URL-encode. You can pass in an object or dictionary, but not lists, strings, or primitives. + /// Throws when passing in a list, a string, or a primitive value. + /// A collection of key value pairs. The keys and values are not URL encoded. + internal static IEnumerable> ToForm(object value) + { + var queryCollection = new List>(); + var json = JsonUtils.SerializeToElement(value); + AssertRootJson(json); + JsonToForm(json, "", queryCollection); + return queryCollection; + } + + private static void AssertRootJson(JsonElement json) + { + switch (json.ValueKind) + { + case JsonValueKind.Object: + break; + case JsonValueKind.Array: + case JsonValueKind.Undefined: + case JsonValueKind.String: + case JsonValueKind.Number: + case JsonValueKind.True: + case JsonValueKind.False: + case JsonValueKind.Null: + default: + throw new global::System.Exception( + $"Only objects can be converted to query string collections. Given type is {json.ValueKind}." + ); + } + } + + private static void JsonToForm( + JsonElement element, + string prefix, + List> parameters + ) + { + switch (element.ValueKind) + { + case JsonValueKind.Object: + foreach (var property in element.EnumerateObject()) + { + var newPrefix = string.IsNullOrEmpty(prefix) + ? property.Name + : $"{prefix}[{property.Name}]"; + + JsonToForm(property.Value, newPrefix, parameters); + } + break; + case JsonValueKind.Array: + var arrayValues = element.EnumerateArray().Select(ValueToString).ToArray(); + parameters.Add( + new KeyValuePair(prefix, string.Join(",", arrayValues)) + ); + break; + case JsonValueKind.Null: + break; + case JsonValueKind.Undefined: + case JsonValueKind.String: + case JsonValueKind.Number: + case JsonValueKind.True: + case JsonValueKind.False: + default: + parameters.Add(new KeyValuePair(prefix, ValueToString(element))); + break; + } + } + + private static void JsonToFormExploded( + JsonElement element, + string prefix, + List> parameters + ) + { + switch (element.ValueKind) + { + case JsonValueKind.Object: + foreach (var property in element.EnumerateObject()) + { + var newPrefix = string.IsNullOrEmpty(prefix) + ? property.Name + : $"{prefix}[{property.Name}]"; + + JsonToFormExploded(property.Value, newPrefix, parameters); + } + + break; + case JsonValueKind.Array: + foreach (var item in element.EnumerateArray()) + { + if ( + item.ValueKind != JsonValueKind.Object + && item.ValueKind != JsonValueKind.Array + ) + { + parameters.Add( + new KeyValuePair(prefix, ValueToString(item)) + ); + } + else + { + JsonToFormExploded(item, prefix, parameters); + } + } + + break; + case JsonValueKind.Null: + break; + case JsonValueKind.Undefined: + case JsonValueKind.String: + case JsonValueKind.Number: + case JsonValueKind.True: + case JsonValueKind.False: + default: + parameters.Add(new KeyValuePair(prefix, ValueToString(element))); + break; + } + } + + private static void JsonToDeepObject( + JsonElement element, + string prefix, + List> parameters + ) + { + switch (element.ValueKind) + { + case JsonValueKind.Object: + foreach (var property in element.EnumerateObject()) + { + var newPrefix = string.IsNullOrEmpty(prefix) + ? property.Name + : $"{prefix}[{property.Name}]"; + + JsonToDeepObject(property.Value, newPrefix, parameters); + } + + break; + case JsonValueKind.Array: + var index = 0; + foreach (var item in element.EnumerateArray()) + { + var newPrefix = $"{prefix}[{index++}]"; + + if ( + item.ValueKind != JsonValueKind.Object + && item.ValueKind != JsonValueKind.Array + ) + { + parameters.Add( + new KeyValuePair(newPrefix, ValueToString(item)) + ); + } + else + { + JsonToDeepObject(item, newPrefix, parameters); + } + } + + break; + case JsonValueKind.Null: + case JsonValueKind.Undefined: + // Skip null and undefined values - don't add parameters for them + break; + case JsonValueKind.String: + case JsonValueKind.Number: + case JsonValueKind.True: + case JsonValueKind.False: + default: + parameters.Add(new KeyValuePair(prefix, ValueToString(element))); + break; + } + } + + private static string ValueToString(JsonElement element) + { + return element.ValueKind switch + { + JsonValueKind.String => element.GetString() ?? "", + JsonValueKind.Number => element.GetRawText(), + JsonValueKind.True => "true", + JsonValueKind.False => "false", + JsonValueKind.Null => "", + _ => element.GetRawText(), + }; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/RawClient.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/RawClient.cs new file mode 100644 index 000000000000..222916404413 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/RawClient.cs @@ -0,0 +1,364 @@ +using global::System.Net.Http; +using global::System.Net.Http.Headers; +using global::System.Text; +using SystemTask = global::System.Threading.Tasks.Task; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Utility class for making raw HTTP requests to the API. +/// +internal partial class RawClient(ClientOptions clientOptions) +{ + private const int MaxRetryDelayMs = 60000; + private const double JitterFactor = 0.2; +#if NET6_0_OR_GREATER + // Use Random.Shared for thread-safe random number generation on .NET 6+ +#else + private static readonly object JitterLock = new(); + private static readonly Random JitterRandom = new(); +#endif + internal int BaseRetryDelay { get; set; } = 1000; + + /// + /// The client options applied on every request. + /// + internal readonly ClientOptions Options = clientOptions; + + internal async global::System.Threading.Tasks.Task SendRequestAsync( + global::SeedCsharpXmlEntities.Core.BaseRequest request, + CancellationToken cancellationToken = default + ) + { + // Apply the request timeout. + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + var timeout = request.Options?.Timeout ?? Options.Timeout; + cts.CancelAfter(timeout); + + var httpRequest = await CreateHttpRequestAsync(request).ConfigureAwait(false); + // Send the request. + return await SendWithRetriesAsync(httpRequest, request.Options, cts.Token) + .ConfigureAwait(false); + } + + internal async global::System.Threading.Tasks.Task SendRequestAsync( + HttpRequestMessage request, + IRequestOptions? options, + CancellationToken cancellationToken = default + ) + { + // Apply the request timeout. + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + var timeout = options?.Timeout ?? Options.Timeout; + cts.CancelAfter(timeout); + + // Send the request. + return await SendWithRetriesAsync(request, options, cts.Token).ConfigureAwait(false); + } + + private static async global::System.Threading.Tasks.Task CloneRequestAsync( + HttpRequestMessage request, + CancellationToken cancellationToken = default + ) + { + var clonedRequest = new HttpRequestMessage(request.Method, request.RequestUri); + clonedRequest.Version = request.Version; + + if (request.Content != null) + { + switch (request.Content) + { + case MultipartContent oldMultipartFormContent: + var originalBoundary = + oldMultipartFormContent + .Headers.ContentType?.Parameters.First(p => + p.Name.Equals("boundary", StringComparison.OrdinalIgnoreCase) + ) + .Value?.Trim('"') + ?? Guid.NewGuid().ToString(); + var newMultipartContent = oldMultipartFormContent switch + { + MultipartFormDataContent => new MultipartFormDataContent(originalBoundary), + _ => new MultipartContent(), + }; + foreach (var content in oldMultipartFormContent) + { + var ms = new MemoryStream(); +#if NET5_0_OR_GREATER + await content.CopyToAsync(ms, cancellationToken).ConfigureAwait(false); +#else + await content.CopyToAsync(ms).ConfigureAwait(false); +#endif + ms.Position = 0; + var newPart = new StreamContent(ms); + foreach (var header in content.Headers) + { + newPart.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + + newMultipartContent.Add(newPart); + } + + clonedRequest.Content = newMultipartContent; + break; + default: + var bodyStream = new MemoryStream(); +#if NET5_0_OR_GREATER + await request + .Content.CopyToAsync(bodyStream, cancellationToken) + .ConfigureAwait(false); +#else + await request.Content.CopyToAsync(bodyStream).ConfigureAwait(false); +#endif + bodyStream.Position = 0; + var clonedContent = new StreamContent(bodyStream); + foreach (var header in request.Content.Headers) + { + clonedContent.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + + clonedRequest.Content = clonedContent; + break; + } + } + + foreach (var header in request.Headers) + { + clonedRequest.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + + return clonedRequest; + } + + /// + /// Sends the request with retries, unless the request content is not retryable, + /// such as stream requests and multipart form data with stream content. + /// + private async global::System.Threading.Tasks.Task SendWithRetriesAsync( + HttpRequestMessage request, + IRequestOptions? options, + CancellationToken cancellationToken + ) + { + var httpClient = options?.HttpClient ?? Options.HttpClient; + var maxRetries = Math.Max(0, options?.MaxRetries ?? Options.MaxRetries); + var isRetryableContent = IsRetryableContent(request); + + if (!isRetryableContent || maxRetries == 0) + { + var response = await httpClient + .SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken) + .ConfigureAwait(false); + return new global::SeedCsharpXmlEntities.Core.ApiResponse + { + StatusCode = (int)response.StatusCode, + Raw = response, + }; + } + + // Always send a clone, never the original: HttpClient (e.g. under HTTP/2) disposes + // request.Content after sending, which would break the next attempt's clone. + HttpResponseMessage? retryResponse = null; + for (var attempt = 0; attempt <= maxRetries; attempt++) + { + if (attempt > 0) + { + var delayMs = GetRetryDelayFromHeaders(retryResponse!, attempt - 1); + await SystemTask.Delay(delayMs, cancellationToken).ConfigureAwait(false); + } + + using var attemptRequest = await CloneRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + retryResponse = await httpClient + .SendAsync( + attemptRequest, + HttpCompletionOption.ResponseHeadersRead, + cancellationToken + ) + .ConfigureAwait(false); + + if (!ShouldRetry(retryResponse)) + { + break; + } + } + + return new global::SeedCsharpXmlEntities.Core.ApiResponse + { + StatusCode = (int)retryResponse!.StatusCode, + Raw = retryResponse, + }; + } + + private static bool ShouldRetry(HttpResponseMessage response) + { + var statusCode = (int)response.StatusCode; + + return statusCode is 408 or 429 or (>= 500); + } + + private static int AddPositiveJitter(int delayMs) + { +#if NET6_0_OR_GREATER + var random = Random.Shared.NextDouble(); +#else + double random; + lock (JitterLock) + { + random = JitterRandom.NextDouble(); + } +#endif + var jitterMultiplier = 1 + random * JitterFactor; + return (int)(delayMs * jitterMultiplier); + } + + private static int AddSymmetricJitter(int delayMs) + { +#if NET6_0_OR_GREATER + var random = Random.Shared.NextDouble(); +#else + double random; + lock (JitterLock) + { + random = JitterRandom.NextDouble(); + } +#endif + var jitterMultiplier = 1 + (random - 0.5) * JitterFactor; + return (int)(delayMs * jitterMultiplier); + } + + private int GetRetryDelayFromHeaders(HttpResponseMessage response, int retryAttempt) + { + if (response.Headers.TryGetValues("Retry-After", out var retryAfterValues)) + { + var retryAfter = retryAfterValues.FirstOrDefault(); + if (!string.IsNullOrEmpty(retryAfter)) + { + if (int.TryParse(retryAfter, out var retryAfterSeconds) && retryAfterSeconds > 0) + { + return Math.Min(retryAfterSeconds * 1000, MaxRetryDelayMs); + } + + if (DateTimeOffset.TryParse(retryAfter, out var retryAfterDate)) + { + var delay = (int)(retryAfterDate - DateTimeOffset.UtcNow).TotalMilliseconds; + if (delay > 0) + { + return Math.Min(delay, MaxRetryDelayMs); + } + } + } + } + + if (response.Headers.TryGetValues("X-RateLimit-Reset", out var rateLimitResetValues)) + { + var rateLimitReset = rateLimitResetValues.FirstOrDefault(); + if ( + !string.IsNullOrEmpty(rateLimitReset) + && long.TryParse(rateLimitReset, out var resetTime) + ) + { + var resetDateTime = DateTimeOffset.FromUnixTimeSeconds(resetTime); + var delay = (int)(resetDateTime - DateTimeOffset.UtcNow).TotalMilliseconds; + if (delay > 0) + { + return AddPositiveJitter(Math.Min(delay, MaxRetryDelayMs)); + } + } + } + + var exponentialDelay = Math.Min(BaseRetryDelay * (1 << retryAttempt), MaxRetryDelayMs); + return AddSymmetricJitter(exponentialDelay); + } + + private static bool IsRetryableContent(HttpRequestMessage request) + { + return request.Content switch + { + IIsRetryableContent c => c.IsRetryable, + StreamContent => false, + MultipartContent content => !content.Any(c => c is StreamContent), + _ => true, + }; + } + + internal async global::System.Threading.Tasks.Task CreateHttpRequestAsync( + global::SeedCsharpXmlEntities.Core.BaseRequest request + ) + { + var url = BuildUrl(request); + var httpRequest = new HttpRequestMessage(request.Method, url); + httpRequest.Content = request.CreateContent(); + SetHeaders(httpRequest, request.Headers); + + return httpRequest; + } + + private string BuildUrl(global::SeedCsharpXmlEntities.Core.BaseRequest request) + { + var baseUrl = request.Options?.BaseUrl ?? request.BaseUrl ?? Options.BaseUrl; + + var trimmedBaseUrl = baseUrl.TrimEnd('/'); + var trimmedBasePath = request.Path.TrimStart('/'); + var url = $"{trimmedBaseUrl}/{trimmedBasePath}"; + + // Append query string if present + if (!string.IsNullOrEmpty(request.QueryString)) + { + return url + request.QueryString; + } + + return url; + } + + private void SetHeaders(HttpRequestMessage httpRequest, Dictionary? headers) + { + if (headers is null) + { + return; + } + + foreach (var kv in headers) + { + if (kv.Value is null) + { + continue; + } + + httpRequest.Headers.TryAddWithoutValidation(kv.Key, kv.Value); + } + } + + private static (Encoding encoding, string? charset, string mediaType) ParseContentTypeOrDefault( + string? contentType, + Encoding encodingFallback, + string mediaTypeFallback + ) + { + var encoding = encodingFallback; + var mediaType = mediaTypeFallback; + string? charset = null; + if (string.IsNullOrEmpty(contentType)) + { + return (encoding, charset, mediaType); + } + + if (!MediaTypeHeaderValue.TryParse(contentType, out var mediaTypeHeaderValue)) + { + return (encoding, charset, mediaType); + } + + if (!string.IsNullOrEmpty(mediaTypeHeaderValue.CharSet)) + { + charset = mediaTypeHeaderValue.CharSet; + encoding = Encoding.GetEncoding(mediaTypeHeaderValue.CharSet); + } + + if (!string.IsNullOrEmpty(mediaTypeHeaderValue.MediaType)) + { + mediaType = mediaTypeHeaderValue.MediaType; + } + + return (encoding, charset, mediaType); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/RawResponse.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/RawResponse.cs new file mode 100644 index 000000000000..bf244dc3c39e --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/RawResponse.cs @@ -0,0 +1,24 @@ +using global::System.Net; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Contains HTTP response metadata including status code, URL, and headers. +/// +public record RawResponse +{ + /// + /// The HTTP status code of the response. + /// + public required HttpStatusCode StatusCode { get; init; } + + /// + /// The request URL that generated this response. + /// + public required Uri Url { get; init; } + + /// + /// The HTTP response headers. + /// + public required Core.ResponseHeaders Headers { get; init; } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/ResponseHeaders.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/ResponseHeaders.cs new file mode 100644 index 000000000000..dc8e31f168ff --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/ResponseHeaders.cs @@ -0,0 +1,108 @@ +using global::System.Collections; +using global::System.Net.Http.Headers; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Represents HTTP response headers with case-insensitive lookup. +/// +public readonly struct ResponseHeaders : IEnumerable +{ + private readonly HttpResponseHeaders? _headers; + private readonly HttpContentHeaders? _contentHeaders; + + private ResponseHeaders(HttpResponseHeaders headers, HttpContentHeaders? contentHeaders) + { + _headers = headers; + _contentHeaders = contentHeaders; + } + + /// + /// Gets the Content-Type header value, if present. + /// + public string? ContentType => _contentHeaders?.ContentType?.ToString(); + + /// + /// Gets the Content-Length header value, if present. + /// + public long? ContentLength => _contentHeaders?.ContentLength; + + /// + /// Creates a ResponseHeaders instance from an HttpResponseMessage. + /// + public static ResponseHeaders FromHttpResponseMessage(HttpResponseMessage response) + { + return new ResponseHeaders(response.Headers, response.Content?.Headers); + } + + /// + /// Tries to get a single header value. Returns the first value if multiple values exist. + /// + public bool TryGetValue(string name, out string? value) + { + if (TryGetValues(name, out var values) && values is not null) + { + value = values.FirstOrDefault(); + return true; + } + + value = null; + return false; + } + + /// + /// Tries to get all values for a header. + /// + public bool TryGetValues(string name, out IEnumerable? values) + { + if (_headers?.TryGetValues(name, out values) == true) + { + return true; + } + + if (_contentHeaders?.TryGetValues(name, out values) == true) + { + return true; + } + + values = null; + return false; + } + + /// + /// Checks if the headers contain a specific header name. + /// + public bool Contains(string name) + { + return _headers?.Contains(name) == true || _contentHeaders?.Contains(name) == true; + } + + /// + /// Gets an enumerator for all headers. + /// + public IEnumerator GetEnumerator() + { + if (_headers is not null) + { + foreach (var header in _headers) + { + yield return new HttpHeader(header.Key, string.Join(", ", header.Value)); + } + } + + if (_contentHeaders is not null) + { + foreach (var header in _contentHeaders) + { + yield return new HttpHeader(header.Key, string.Join(", ", header.Value)); + } + } + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} + +/// +/// Represents a single HTTP header. +/// +public readonly record struct HttpHeader(string Name, string Value); diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/StreamRequest.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/StreamRequest.cs new file mode 100644 index 000000000000..029f1a9ceedd --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/StreamRequest.cs @@ -0,0 +1,29 @@ +using global::System.Net.Http; +using global::System.Net.Http.Headers; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// The request object to be sent for streaming uploads. +/// +internal record StreamRequest : BaseRequest +{ + internal Stream? Body { get; init; } + + internal override HttpContent? CreateContent() + { + if (Body is null) + { + return null; + } + + var content = new StreamContent(Body) + { + Headers = + { + ContentType = MediaTypeHeaderValue.Parse(ContentType ?? "application/octet-stream"), + }, + }; + return content; + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/StringEnum.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/StringEnum.cs new file mode 100644 index 000000000000..1c3dfea3287b --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/StringEnum.cs @@ -0,0 +1,6 @@ +namespace SeedCsharpXmlEntities.Core; + +public interface IStringEnum : IEquatable +{ + public string Value { get; } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/StringEnumExtensions.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/StringEnumExtensions.cs new file mode 100644 index 000000000000..1882c6dd461e --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/StringEnumExtensions.cs @@ -0,0 +1,6 @@ +namespace SeedCsharpXmlEntities.Core; + +internal static class StringEnumExtensions +{ + public static string Stringify(this IStringEnum stringEnum) => stringEnum.Value; +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/ValueConvert.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/ValueConvert.cs new file mode 100644 index 000000000000..d39f1360b663 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Core/ValueConvert.cs @@ -0,0 +1,115 @@ +using global::System.Globalization; + +namespace SeedCsharpXmlEntities.Core; + +/// +/// Convert values to string for path and query parameters. +/// +public static class ValueConvert +{ + internal static string ToPathParameterString(T value) => ToString(value); + + internal static string ToPathParameterString(bool v) => ToString(v); + + internal static string ToPathParameterString(int v) => ToString(v); + + internal static string ToPathParameterString(long v) => ToString(v); + + internal static string ToPathParameterString(float v) => ToString(v); + + internal static string ToPathParameterString(double v) => ToString(v); + + internal static string ToPathParameterString(decimal v) => ToString(v); + + internal static string ToPathParameterString(short v) => ToString(v); + + internal static string ToPathParameterString(ushort v) => ToString(v); + + internal static string ToPathParameterString(uint v) => ToString(v); + + internal static string ToPathParameterString(ulong v) => ToString(v); + + internal static string ToPathParameterString(string v) => + QueryStringBuilder.EncodePathSegment(v); + + internal static string ToPathParameterString(char v) => ToString(v); + + internal static string ToPathParameterString(Guid v) => ToString(v); + + internal static string ToQueryStringValue(T value) => value is null ? "" : ToString(value); + + internal static string ToQueryStringValue(bool v) => ToString(v); + + internal static string ToQueryStringValue(int v) => ToString(v); + + internal static string ToQueryStringValue(long v) => ToString(v); + + internal static string ToQueryStringValue(float v) => ToString(v); + + internal static string ToQueryStringValue(double v) => ToString(v); + + internal static string ToQueryStringValue(decimal v) => ToString(v); + + internal static string ToQueryStringValue(short v) => ToString(v); + + internal static string ToQueryStringValue(ushort v) => ToString(v); + + internal static string ToQueryStringValue(uint v) => ToString(v); + + internal static string ToQueryStringValue(ulong v) => ToString(v); + + internal static string ToQueryStringValue(string v) => v is null ? "" : v; + + internal static string ToQueryStringValue(char v) => ToString(v); + + internal static string ToQueryStringValue(Guid v) => ToString(v); + + internal static string ToString(T value) + { + return value switch + { + null => "null", + string str => str, + true => "true", + false => "false", + int i => ToString(i), + long l => ToString(l), + float f => ToString(f), + double d => ToString(d), + decimal dec => ToString(dec), + short s => ToString(s), + ushort u => ToString(u), + uint u => ToString(u), + ulong u => ToString(u), + char c => ToString(c), + Guid guid => ToString(guid), + _ => JsonUtils.SerializeRelaxedEscaping(value, value.GetType()).Trim('"'), + }; + } + + internal static string ToString(bool v) => v ? "true" : "false"; + + internal static string ToString(int v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(long v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(float v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(double v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(decimal v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(short v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(ushort v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(uint v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(ulong v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(char v) => v.ToString(CultureInfo.InvariantCulture); + + internal static string ToString(string v) => v; + + internal static string ToString(Guid v) => v.ToString("D"); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/ISeedCsharpXmlEntitiesClient.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/ISeedCsharpXmlEntitiesClient.cs new file mode 100644 index 000000000000..0810efe8d947 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/ISeedCsharpXmlEntitiesClient.cs @@ -0,0 +1,12 @@ +namespace SeedCsharpXmlEntities; + +public partial interface ISeedCsharpXmlEntitiesClient +{ + /// + /// Get timezone information with + offset + /// + WithRawResponseTask GetTimeZoneAsync( + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.Custom.props b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.Custom.props new file mode 100644 index 000000000000..17a84cada530 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.Custom.props @@ -0,0 +1,20 @@ + + + + diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj new file mode 100644 index 000000000000..ed4cb9dd9995 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/SeedCsharpXmlEntities.csproj @@ -0,0 +1,82 @@ + + + net462;net8.0;net9.0;netstandard2.0 + enable + 12 + enable + 0.0.1 + $(Version) + $(Version) + README.md + true + $(NoWarn);CS1591 + An SDK for the XML entities API. + Fern,Acme + acme;sdk + Copyright (c) Acme, Inc. <acme@example.com> + https://example.com/docs + https://github.com/acme/acme-dotnet + git + true + snupkg + true + true + true + true + + + + false + + + $(DefineConstants);USE_PORTABLE_DATE_ONLY + true + + + + + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + + + + <_Parameter1>SeedCsharpXmlEntities.Test + + + + + diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/SeedCsharpXmlEntitiesClient.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/SeedCsharpXmlEntitiesClient.cs new file mode 100644 index 000000000000..dcdfb1038d52 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/SeedCsharpXmlEntitiesClient.cs @@ -0,0 +1,127 @@ +using global::System.Text.Json; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities; + +public partial class SeedCsharpXmlEntitiesClient : ISeedCsharpXmlEntitiesClient +{ + private readonly RawClient _client; + + public SeedCsharpXmlEntitiesClient(ClientOptions? clientOptions = null) + { + clientOptions ??= new ClientOptions(); + var platformHeaders = new Headers( + new Dictionary() + { + { "X-Fern-Language", "C#" }, + { "X-Fern-SDK-Name", "SeedCsharpXmlEntities" }, + { "X-Fern-SDK-Version", global::SeedCsharpXmlEntities.Version.Current }, + { "User-Agent", "Ferncsharp-xml-entities/0.0.1" }, + } + ); + foreach (var header in platformHeaders) + { + if (!clientOptions.Headers.ContainsKey(header.Key)) + { + clientOptions.Headers[header.Key] = header.Value; + } + } + _client = new RawClient(clientOptions); + } + + private async Task> GetTimeZoneAsyncCore( + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _queryString = new SeedCsharpXmlEntities.Core.QueryStringBuilder.Builder(capacity: 0) + .MergeAdditional(options?.AdditionalQueryParameters) + .Build(); + var _headers = await new SeedCsharpXmlEntities.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethod.Get, + Path = "/timezone", + QueryString = _queryString, + Headers = _headers, + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + var responseData = JsonUtils.Deserialize(responseBody)!; + return new WithRawResponse() + { + Data = responseData, + RawResponse = new SeedCsharpXmlEntities.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }, + }; + } + catch (JsonException e) + { + throw new SeedCsharpXmlEntitiesApiException( + "Failed to deserialize response", + response.StatusCode, + responseBody, + e, + rawResponse: new SeedCsharpXmlEntities.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + throw new SeedCsharpXmlEntitiesApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody, + rawResponse: new SeedCsharpXmlEntities.RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + } + ); + } + } + + /// + /// Get timezone information with + offset + /// + /// + /// await client.GetTimeZoneAsync(); + /// + public WithRawResponseTask GetTimeZoneAsync( + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask( + GetTimeZoneAsyncCore(options, cancellationToken) + ); + } +} diff --git a/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Types/TimeZoneModel.cs b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Types/TimeZoneModel.cs new file mode 100644 index 000000000000..c1a59a67ff35 --- /dev/null +++ b/seed/csharp-sdk/csharp-xml-entities/package-metadata/src/SeedCsharpXmlEntities/Types/TimeZoneModel.cs @@ -0,0 +1,65 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedCsharpXmlEntities.Core; + +namespace SeedCsharpXmlEntities; + +/// +/// Model demonstrating HTML entity bug in C# XML documentation. +/// This description contains HTML entities that are not valid in XML. +/// +[Serializable] +public record TimeZoneModel : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + /// + /// Format is UTC + offset notation (e.g., +05:30) + /// + [JsonPropertyName("timeZoneOffset")] + public required string TimeZoneOffset { get; set; } + + /// + /// Expression: A + B - C × D ÷ E + /// + [JsonPropertyName("mathExpression")] + public required string MathExpression { get; set; } + + /// + /// This uses valid XML entity: A < B & C > D + /// + [JsonPropertyName("validEntity")] + public required string ValidEntity { get; set; } + + /// + /// Special characters: … · © + /// + [JsonPropertyName("specialChars")] + public string? SpecialChars { get; set; } + + /// + /// See see here for details + /// + [JsonPropertyName("documentationLink")] + public string? DocumentationLink { get; set; } + + /// + /// See see here for details + /// + [JsonPropertyName("escapedDocumentationLink")] + public string? EscapedDocumentationLink { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/discriminated-union-with-nested-oneof/README.md b/seed/csharp-sdk/discriminated-union-with-nested-oneof/README.md index 18f5e0e82d39..bea2ae095b49 100644 --- a/seed/csharp-sdk/discriminated-union-with-nested-oneof/README.md +++ b/seed/csharp-sdk/discriminated-union-with-nested-oneof/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -102,7 +105,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreateAstAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -115,7 +118,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreateAstAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -145,7 +148,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreateAstAsync(...); +var parsedData = await client.CreateAstAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/SeedApi.csproj index 0e310e995d05..c88edfd4c950 100644 --- a/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/discriminated-union-with-nested-oneof/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/discriminated-union-with-nested-oneof/fern + https://github.com/discriminated-union-with-nested-oneof/fern + git true diff --git a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples.Test/Utils/OptionalComparer.cs index 7d06210e0e45..8f14737bac45 100644 --- a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/Extensions.cs b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/Extensions.cs index 1a7e91ca2f3a..af9d8e9254e1 100644 --- a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/Extensions.cs +++ b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/NullableAttribute.cs b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/NullableAttribute.cs index 8881c0bf5ec3..ecc08493f58c 100644 --- a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedDollarStringExamples.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedDollarStringExamples.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/Optional.cs b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/Optional.cs index 46afba78bff3..5a547b9d26bc 100644 --- a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/Optional.cs +++ b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/OptionalAttribute.cs b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/OptionalAttribute.cs index e6813b744214..bd2b7710ad50 100644 --- a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedDollarStringExamples.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/QueryStringBuilder.cs b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/QueryStringBuilder.cs index 3c13b9ca65d1..460b34c4534e 100644 --- a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/SeedDollarStringExamples.csproj b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/SeedDollarStringExamples.csproj index 689a58271c44..7b4513f06724 100644 --- a/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/SeedDollarStringExamples.csproj +++ b/seed/csharp-sdk/dollar-string-examples/src/SeedDollarStringExamples/SeedDollarStringExamples.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/dollar-string-examples/fern + https://github.com/dollar-string-examples/fern + git true diff --git a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients.Test/Utils/OptionalComparer.cs index d76882adddc3..52c8dee13263 100644 --- a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/Extensions.cs b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/Extensions.cs index 43f9240e89c3..228eb76872e7 100644 --- a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/Extensions.cs +++ b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/NullableAttribute.cs b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/NullableAttribute.cs index 63979c790c97..900a36d92388 100644 --- a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedEmptyClients.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedEmptyClients.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/Optional.cs b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/Optional.cs index c557f41a6bcd..b3dbe0da2700 100644 --- a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/Optional.cs +++ b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/OptionalAttribute.cs b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/OptionalAttribute.cs index 4183263854ad..2d2f019aa1e8 100644 --- a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedEmptyClients.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/QueryStringBuilder.cs b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/QueryStringBuilder.cs index 5ac492e2e5fc..42056443f4eb 100644 --- a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/SeedEmptyClients.csproj b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/SeedEmptyClients.csproj index 055c2c926ac9..17c6abe35cec 100644 --- a/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/SeedEmptyClients.csproj +++ b/seed/csharp-sdk/empty-clients/src/SeedEmptyClients/SeedEmptyClients.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/empty-clients/fern + https://github.com/empty-clients/fern + git true diff --git a/seed/csharp-sdk/endpoint-security-auth/README.md b/seed/csharp-sdk/endpoint-security-auth/README.md index e200d174f1f3..7d85b285d31e 100644 --- a/seed/csharp-sdk/endpoint-security-auth/README.md +++ b/seed/csharp-sdk/endpoint-security-auth/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -116,7 +119,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -129,7 +132,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -159,7 +162,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenAsync(...); +var parsedData = await client.Auth.GetTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth.Test/Utils/OptionalComparer.cs index 1748fac087ab..a02b7b8075b1 100644 --- a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/Extensions.cs b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/Extensions.cs index bb234aae8548..5ebe439f1de3 100644 --- a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/Extensions.cs +++ b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/NullableAttribute.cs index 437f427c3270..f29efa89a9c8 100644 --- a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedEndpointSecurityAuth.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedEndpointSecurityAuth.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/Optional.cs b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/Optional.cs index 99259d0ab4b8..4dda2ae0f0cb 100644 --- a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/Optional.cs +++ b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/OptionalAttribute.cs index ee8dbe05f34b..86a0da09afe6 100644 --- a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedEndpointSecurityAuth.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/QueryStringBuilder.cs index a1e44efb2af6..c02b9a7c2e12 100644 --- a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/SeedEndpointSecurityAuth.csproj b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/SeedEndpointSecurityAuth.csproj index 848069d32098..a97100ca09b2 100644 --- a/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/SeedEndpointSecurityAuth.csproj +++ b/seed/csharp-sdk/endpoint-security-auth/src/SeedEndpointSecurityAuth/SeedEndpointSecurityAuth.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/endpoint-security-auth/fern + https://github.com/endpoint-security-auth/fern + git true diff --git a/seed/csharp-sdk/enum/forward-compatible-enums/README.md b/seed/csharp-sdk/enum/forward-compatible-enums/README.md index c35710df7864..2e08a3706ca5 100644 --- a/seed/csharp-sdk/enum/forward-compatible-enums/README.md +++ b/seed/csharp-sdk/enum/forward-compatible-enums/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -110,7 +113,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Headers.SendAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -123,7 +126,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Headers.SendAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -153,7 +156,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Headers.SendAsync(...); +var parsedData = await client.Headers.SendAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum.Test/Utils/OptionalComparer.cs index e07516625dc0..663bbb9b03e0 100644 --- a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/Extensions.cs b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/Extensions.cs index 4ca6b40a7f6a..29952a252025 100644 --- a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/Extensions.cs +++ b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/NullableAttribute.cs b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/NullableAttribute.cs index 15906218f898..54f272b0ddc5 100644 --- a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedEnum.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedEnum.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/Optional.cs b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/Optional.cs index a57cecc1bc7b..aef569dc57e9 100644 --- a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/Optional.cs +++ b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/OptionalAttribute.cs b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/OptionalAttribute.cs index 8015a069af41..d65d75615109 100644 --- a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedEnum.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/QueryStringBuilder.cs b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/QueryStringBuilder.cs index 1edfa7517055..fb79a93f455b 100644 --- a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/SeedEnum.csproj b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/SeedEnum.csproj index 81f07f8af854..67b36fa86c2a 100644 --- a/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/SeedEnum.csproj +++ b/seed/csharp-sdk/enum/forward-compatible-enums/src/SeedEnum/SeedEnum.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/enum/fern + https://github.com/enum/fern + git true diff --git a/seed/csharp-sdk/enum/plain-enums/README.md b/seed/csharp-sdk/enum/plain-enums/README.md index 60ef496b0feb..8c2ac493931f 100644 --- a/seed/csharp-sdk/enum/plain-enums/README.md +++ b/seed/csharp-sdk/enum/plain-enums/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Headers.SendAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Headers.SendAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Headers.SendAsync(...); +var parsedData = await client.Headers.SendAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum.Test/Utils/OptionalComparer.cs index e07516625dc0..663bbb9b03e0 100644 --- a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/Extensions.cs b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/Extensions.cs index 4ca6b40a7f6a..29952a252025 100644 --- a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/Extensions.cs +++ b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/NullableAttribute.cs b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/NullableAttribute.cs index 15906218f898..54f272b0ddc5 100644 --- a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedEnum.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedEnum.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/Optional.cs b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/Optional.cs index a57cecc1bc7b..aef569dc57e9 100644 --- a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/Optional.cs +++ b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/OptionalAttribute.cs b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/OptionalAttribute.cs index 8015a069af41..d65d75615109 100644 --- a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedEnum.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/QueryStringBuilder.cs b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/QueryStringBuilder.cs index 1edfa7517055..fb79a93f455b 100644 --- a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/SeedEnum.csproj b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/SeedEnum.csproj index 81f07f8af854..67b36fa86c2a 100644 --- a/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/SeedEnum.csproj +++ b/seed/csharp-sdk/enum/plain-enums/src/SeedEnum/SeedEnum.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/enum/fern + https://github.com/enum/fern + git true diff --git a/seed/csharp-sdk/error-property/README.md b/seed/csharp-sdk/error-property/README.md index 01475d72114e..ad011add1a99 100644 --- a/seed/csharp-sdk/error-property/README.md +++ b/seed/csharp-sdk/error-property/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.PropertyBasedError.ThrowErrorAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.PropertyBasedError.ThrowErrorAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.PropertyBasedError.ThrowErrorAsync(...); +var parsedData = await client.PropertyBasedError.ThrowErrorAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/error-property/src/SeedErrorProperty.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/error-property/src/SeedErrorProperty.Test/Utils/OptionalComparer.cs index b3f00aaca920..6799752651d4 100644 --- a/seed/csharp-sdk/error-property/src/SeedErrorProperty.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/error-property/src/SeedErrorProperty.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/Extensions.cs b/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/Extensions.cs index 22a22bc4033f..c1d515daba04 100644 --- a/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/Extensions.cs +++ b/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/NullableAttribute.cs b/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/NullableAttribute.cs index 2c348778bafc..7fee8f1a1fd6 100644 --- a/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedErrorProperty.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedErrorProperty.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/Optional.cs b/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/Optional.cs index a927b7be01ba..4cb3018d7945 100644 --- a/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/Optional.cs +++ b/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/OptionalAttribute.cs b/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/OptionalAttribute.cs index a89aa97e07eb..c44d0a12b82b 100644 --- a/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedErrorProperty.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/QueryStringBuilder.cs b/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/QueryStringBuilder.cs index 66c24ab8a9b8..30ce026daf78 100644 --- a/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/error-property/src/SeedErrorProperty/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/error-property/src/SeedErrorProperty/SeedErrorProperty.csproj b/seed/csharp-sdk/error-property/src/SeedErrorProperty/SeedErrorProperty.csproj index 03c395f82ad4..40892f8ec94c 100644 --- a/seed/csharp-sdk/error-property/src/SeedErrorProperty/SeedErrorProperty.csproj +++ b/seed/csharp-sdk/error-property/src/SeedErrorProperty/SeedErrorProperty.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/error-property/fern + https://github.com/error-property/fern + git true diff --git a/seed/csharp-sdk/errors/README.md b/seed/csharp-sdk/errors/README.md index 58f8a878db66..c3e165f31271 100644 --- a/seed/csharp-sdk/errors/README.md +++ b/seed/csharp-sdk/errors/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Simple.FooWithoutEndpointErrorAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Simple.FooWithoutEndpointErrorAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Simple.FooWithoutEndpointErrorAsync(...); +var parsedData = await client.Simple.FooWithoutEndpointErrorAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/errors/src/SeedErrors.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/errors/src/SeedErrors.Test/Utils/OptionalComparer.cs index 1e0d20b869d1..62e0cae7056c 100644 --- a/seed/csharp-sdk/errors/src/SeedErrors.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/errors/src/SeedErrors.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/errors/src/SeedErrors/Core/Extensions.cs b/seed/csharp-sdk/errors/src/SeedErrors/Core/Extensions.cs index c517b7a91c36..3e90b1e5b3db 100644 --- a/seed/csharp-sdk/errors/src/SeedErrors/Core/Extensions.cs +++ b/seed/csharp-sdk/errors/src/SeedErrors/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/errors/src/SeedErrors/Core/NullableAttribute.cs b/seed/csharp-sdk/errors/src/SeedErrors/Core/NullableAttribute.cs index afb31d590ffa..d1a6a3cfd27d 100644 --- a/seed/csharp-sdk/errors/src/SeedErrors/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/errors/src/SeedErrors/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedErrors.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedErrors.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/errors/src/SeedErrors/Core/Optional.cs b/seed/csharp-sdk/errors/src/SeedErrors/Core/Optional.cs index 764957ab0155..790e2ab73bcb 100644 --- a/seed/csharp-sdk/errors/src/SeedErrors/Core/Optional.cs +++ b/seed/csharp-sdk/errors/src/SeedErrors/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/errors/src/SeedErrors/Core/OptionalAttribute.cs b/seed/csharp-sdk/errors/src/SeedErrors/Core/OptionalAttribute.cs index a4551b3a91f1..338d2f66d048 100644 --- a/seed/csharp-sdk/errors/src/SeedErrors/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/errors/src/SeedErrors/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedErrors.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/errors/src/SeedErrors/Core/QueryStringBuilder.cs b/seed/csharp-sdk/errors/src/SeedErrors/Core/QueryStringBuilder.cs index 113fccff1006..d059609376fd 100644 --- a/seed/csharp-sdk/errors/src/SeedErrors/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/errors/src/SeedErrors/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/errors/src/SeedErrors/SeedErrors.csproj b/seed/csharp-sdk/errors/src/SeedErrors/SeedErrors.csproj index d92fa9b96513..7504d004abcc 100644 --- a/seed/csharp-sdk/errors/src/SeedErrors/SeedErrors.csproj +++ b/seed/csharp-sdk/errors/src/SeedErrors/SeedErrors.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/errors/fern + https://github.com/errors/fern + git true diff --git a/seed/csharp-sdk/examples/no-custom-config/README.md b/seed/csharp-sdk/examples/no-custom-config/README.md index 3684bbc9ee0a..d7b876cefcca 100644 --- a/seed/csharp-sdk/examples/no-custom-config/README.md +++ b/seed/csharp-sdk/examples/no-custom-config/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -116,7 +119,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.EchoAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -129,7 +132,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.EchoAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -159,7 +162,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.EchoAsync(...); +var parsedData = await client.EchoAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples.Test/Utils/OptionalComparer.cs index 1250f90ee958..0eb4a2a1b8d5 100644 --- a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/Extensions.cs b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/Extensions.cs index 0dc9ca8446b7..3ec21f71437e 100644 --- a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/Extensions.cs +++ b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/NullableAttribute.cs b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/NullableAttribute.cs index f5e23626d905..6f3c64bf696b 100644 --- a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedExamples.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedExamples.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/Optional.cs b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/Optional.cs index 986cfb0b673d..eb80162eb160 100644 --- a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/Optional.cs +++ b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/OptionalAttribute.cs b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/OptionalAttribute.cs index a206e2a0446a..48ac99f2b0b5 100644 --- a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedExamples.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/QueryStringBuilder.cs b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/QueryStringBuilder.cs index 5ae94d309a9d..246e488089f6 100644 --- a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/SeedExamples.csproj b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/SeedExamples.csproj index 2e46d901a059..2743ab956339 100644 --- a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/SeedExamples.csproj +++ b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/SeedExamples.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/examples/fern + https://github.com/examples/fern + git true diff --git a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Service/ServiceClient.cs b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Service/ServiceClient.cs index 9bddaa46d911..59e0ec22ab28 100644 --- a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Service/ServiceClient.cs +++ b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Service/ServiceClient.cs @@ -701,7 +701,7 @@ public WithRawResponseTask CreateBigEntityAsync( } /// - /// await client.Service.RefreshTokenAsync(); + /// await client.Service.RefreshTokenAsync(new RefreshTokenRequest { Ttl = 420 }); /// public WithRawResponseTask RefreshTokenAsync( RefreshTokenRequest? request, diff --git a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Types/Types/Exception.cs b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Types/Types/Exception.cs index fde9a79053c1..7c0a20c8afe0 100644 --- a/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Types/Types/Exception.cs +++ b/seed/csharp-sdk/examples/no-custom-config/src/SeedExamples/Types/Types/Exception.cs @@ -67,7 +67,7 @@ public SeedExamples.ExceptionInfo AsGeneric() => : throw new global::System.Exception("Exception.Type is not 'generic'"); /// - /// Returns the value as a if is 'timeout', otherwise throws an exception. + /// Returns the value as a if is 'timeout', otherwise throws an exception. /// /// Thrown when is not 'timeout'. public object? AsTimeout() => @@ -122,7 +122,7 @@ public bool TryAsGeneric(out SeedExamples.ExceptionInfo? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsTimeout(out object? value) { diff --git a/seed/csharp-sdk/examples/readme-config/README.md b/seed/csharp-sdk/examples/readme-config/README.md index a670b1360544..5285624ce118 100644 --- a/seed/csharp-sdk/examples/readme-config/README.md +++ b/seed/csharp-sdk/examples/readme-config/README.md @@ -36,6 +36,9 @@ API reference documentation is available [here](https://www.docs.fernapi.com). ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -162,7 +165,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.CreateMovieAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -175,7 +178,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.GetMovieAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -184,7 +187,7 @@ var response = await client.Service.GetMovieAsync( var response = await client.Service.CreateMovieAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -214,7 +217,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.CreateMovieAsync(...); +var parsedData = await client.Service.CreateMovieAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/examples/readme-config/src/SeedExamples.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/examples/readme-config/src/SeedExamples.Test/Utils/OptionalComparer.cs index 1250f90ee958..0eb4a2a1b8d5 100644 --- a/seed/csharp-sdk/examples/readme-config/src/SeedExamples.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/examples/readme-config/src/SeedExamples.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/Extensions.cs b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/Extensions.cs index 0dc9ca8446b7..3ec21f71437e 100644 --- a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/Extensions.cs +++ b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/NullableAttribute.cs b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/NullableAttribute.cs index f5e23626d905..6f3c64bf696b 100644 --- a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedExamples.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedExamples.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/Optional.cs b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/Optional.cs index 986cfb0b673d..eb80162eb160 100644 --- a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/Optional.cs +++ b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/OptionalAttribute.cs b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/OptionalAttribute.cs index a206e2a0446a..48ac99f2b0b5 100644 --- a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedExamples.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/QueryStringBuilder.cs b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/QueryStringBuilder.cs index 5ae94d309a9d..246e488089f6 100644 --- a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/SeedExamples.csproj b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/SeedExamples.csproj index 2e46d901a059..2743ab956339 100644 --- a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/SeedExamples.csproj +++ b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/SeedExamples.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/examples/fern + https://github.com/examples/fern + git true diff --git a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Service/ServiceClient.cs b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Service/ServiceClient.cs index 9bddaa46d911..59e0ec22ab28 100644 --- a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Service/ServiceClient.cs +++ b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Service/ServiceClient.cs @@ -701,7 +701,7 @@ public WithRawResponseTask CreateBigEntityAsync( } /// - /// await client.Service.RefreshTokenAsync(); + /// await client.Service.RefreshTokenAsync(new RefreshTokenRequest { Ttl = 420 }); /// public WithRawResponseTask RefreshTokenAsync( RefreshTokenRequest? request, diff --git a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Types/Types/Exception.cs b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Types/Types/Exception.cs index fde9a79053c1..7c0a20c8afe0 100644 --- a/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Types/Types/Exception.cs +++ b/seed/csharp-sdk/examples/readme-config/src/SeedExamples/Types/Types/Exception.cs @@ -67,7 +67,7 @@ public SeedExamples.ExceptionInfo AsGeneric() => : throw new global::System.Exception("Exception.Type is not 'generic'"); /// - /// Returns the value as a if is 'timeout', otherwise throws an exception. + /// Returns the value as a if is 'timeout', otherwise throws an exception. /// /// Thrown when is not 'timeout'. public object? AsTimeout() => @@ -122,7 +122,7 @@ public bool TryAsGeneric(out SeedExamples.ExceptionInfo? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsTimeout(out object? value) { diff --git a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/README.md b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/README.md index 016292ae33f6..d7acfee9e59e 100644 --- a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/README.md +++ b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -124,7 +127,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -137,7 +140,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -167,7 +170,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); +var parsedData = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive.Test/Utils/OptionalComparer.cs index 6cd4f6753570..33194e3dfece 100644 --- a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/Extensions.cs b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/Extensions.cs index 7a9af98fd1b0..5aa245a72e8d 100644 --- a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/Extensions.cs +++ b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/NullableAttribute.cs b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/NullableAttribute.cs index b7060ccecf98..22a72c62aafa 100644 --- a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedExhaustive.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedExhaustive.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/Optional.cs b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/Optional.cs index 40b24af7ff1d..eb807bfa6ccd 100644 --- a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/Optional.cs +++ b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/OptionalAttribute.cs b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/OptionalAttribute.cs index 8f18675316ca..d8c4c2081140 100644 --- a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedExhaustive.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/QueryStringBuilder.cs b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/QueryStringBuilder.cs index 7ac49dc02ab6..1d0579cb7848 100644 --- a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs index 62ee5af1d3c3..2e78c993156a 100644 --- a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs +++ b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs @@ -1181,12 +1181,6 @@ public WithRawResponseTask ModifyWithInlinePathAsync( /// /// POST bytes with path param returning object /// - /// - /// await client.Endpoints.Params.UploadWithPathAsync( - /// "upload-path", - /// new MemoryStream(Encoding.UTF8.GetBytes("[bytes]")) - /// ); - /// public WithRawResponseTask UploadWithPathAsync( string param, Stream request, diff --git a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/SeedExhaustive.csproj b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/SeedExhaustive.csproj index e2fc7bf743e9..3cdb5232e256 100644 --- a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/SeedExhaustive.csproj +++ b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/SeedExhaustive.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/exhaustive/fern + https://github.com/exhaustive/fern + git true diff --git a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs index 55a62fded413..97a4aa9f4f38 100644 --- a/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs +++ b/seed/csharp-sdk/exhaustive/auto-generate-idempotency-key/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs @@ -26,11 +26,11 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - *: Can interfere with comment blocks /// - /**: JSDoc comment start /// - ** /: JSDoc comment end - /// - &: HTML entities + /// - &: HTML entities /// /// XMLDoc (C#): /// - <: >: XML tags - /// - &: ': ": <: >: XML special characters + /// - &: ': ": <: >: XML special characters /// - {: }: Used for interpolated strings /// - ///: Comment marker /// - /**: Block comment start @@ -44,7 +44,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// Javadoc (Java): /// - @: Used for Javadoc tags /// - <: >: HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - *: Can interfere with comment blocks /// - /**: Javadoc comment start /// - ** /: Javadoc comment end @@ -53,7 +53,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - \: Used for Doxygen commands /// - @: Alternative command prefix /// - <: >: XML/HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - /**: C-style comment start /// - ** /: C-style comment end /// @@ -76,7 +76,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - /**: PHPDoc comment start /// - ** /: PHPDoc comment end /// - *: Can interfere with comment blocks - /// - &: HTML entities + /// - &: HTML entities /// [JsonPropertyName("string")] public required string String { get; set; } diff --git a/seed/csharp-sdk/exhaustive/explicit-namespaces/README.md b/seed/csharp-sdk/exhaustive/explicit-namespaces/README.md index 47c8de02396a..97f4ef6902b0 100644 --- a/seed/csharp-sdk/exhaustive/explicit-namespaces/README.md +++ b/seed/csharp-sdk/exhaustive/explicit-namespaces/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -124,7 +127,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -137,7 +140,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -167,7 +170,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); +var parsedData = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive.Test/Utils/OptionalComparer.cs index 6cd4f6753570..33194e3dfece 100644 --- a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/Extensions.cs b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/Extensions.cs index 7a9af98fd1b0..5aa245a72e8d 100644 --- a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/Extensions.cs +++ b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/NullableAttribute.cs b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/NullableAttribute.cs index b7060ccecf98..22a72c62aafa 100644 --- a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedExhaustive.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedExhaustive.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/Optional.cs b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/Optional.cs index 40b24af7ff1d..eb807bfa6ccd 100644 --- a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/Optional.cs +++ b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/OptionalAttribute.cs b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/OptionalAttribute.cs index 8f18675316ca..d8c4c2081140 100644 --- a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedExhaustive.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/QueryStringBuilder.cs b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/QueryStringBuilder.cs index 7ac49dc02ab6..1d0579cb7848 100644 --- a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs index 088705fe9625..6fd20584d9f1 100644 --- a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs +++ b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs @@ -1177,12 +1177,6 @@ public WithRawResponseTask ModifyWithInlinePathAsync( /// /// POST bytes with path param returning object /// - /// - /// await client.Endpoints.Params.UploadWithPathAsync( - /// "upload-path", - /// new MemoryStream(Encoding.UTF8.GetBytes("[bytes]")) - /// ); - /// public WithRawResponseTask UploadWithPathAsync( string param, Stream request, diff --git a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/SeedExhaustive.csproj b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/SeedExhaustive.csproj index e2fc7bf743e9..3cdb5232e256 100644 --- a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/SeedExhaustive.csproj +++ b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/SeedExhaustive.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/exhaustive/fern + https://github.com/exhaustive/fern + git true diff --git a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs index 89f2178f5965..f7a1bb66aaba 100644 --- a/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs +++ b/seed/csharp-sdk/exhaustive/explicit-namespaces/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs @@ -26,11 +26,11 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - *: Can interfere with comment blocks /// - /**: JSDoc comment start /// - ** /: JSDoc comment end - /// - &: HTML entities + /// - &: HTML entities /// /// XMLDoc (C#): /// - <: >: XML tags - /// - &: ': ": <: >: XML special characters + /// - &: ': ": <: >: XML special characters /// - {: }: Used for interpolated strings /// - ///: Comment marker /// - /**: Block comment start @@ -44,7 +44,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// Javadoc (Java): /// - @: Used for Javadoc tags /// - <: >: HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - *: Can interfere with comment blocks /// - /**: Javadoc comment start /// - ** /: Javadoc comment end @@ -53,7 +53,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - \: Used for Doxygen commands /// - @: Alternative command prefix /// - <: >: XML/HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - /**: C-style comment start /// - ** /: C-style comment end /// @@ -76,7 +76,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - /**: PHPDoc comment start /// - ** /: PHPDoc comment end /// - *: Can interfere with comment blocks - /// - &: HTML entities + /// - &: HTML entities /// [JsonPropertyName("string")] public required string String { get; set; } diff --git a/seed/csharp-sdk/exhaustive/include-exception-handler/README.md b/seed/csharp-sdk/exhaustive/include-exception-handler/README.md index 016292ae33f6..d7acfee9e59e 100644 --- a/seed/csharp-sdk/exhaustive/include-exception-handler/README.md +++ b/seed/csharp-sdk/exhaustive/include-exception-handler/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -124,7 +127,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -137,7 +140,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -167,7 +170,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); +var parsedData = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive.Test/Utils/OptionalComparer.cs index 6cd4f6753570..33194e3dfece 100644 --- a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/Extensions.cs b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/Extensions.cs index 7a9af98fd1b0..5aa245a72e8d 100644 --- a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/Extensions.cs +++ b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/NullableAttribute.cs b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/NullableAttribute.cs index b7060ccecf98..22a72c62aafa 100644 --- a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedExhaustive.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedExhaustive.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/Optional.cs b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/Optional.cs index 40b24af7ff1d..eb807bfa6ccd 100644 --- a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/Optional.cs +++ b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/OptionalAttribute.cs b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/OptionalAttribute.cs index 8f18675316ca..d8c4c2081140 100644 --- a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedExhaustive.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/QueryStringBuilder.cs b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/QueryStringBuilder.cs index 7ac49dc02ab6..1d0579cb7848 100644 --- a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs index 648198fe7732..22b6a891b25c 100644 --- a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs +++ b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs @@ -1293,12 +1293,6 @@ public WithRawResponseTask ModifyWithInlinePathAsync( /// /// POST bytes with path param returning object /// - /// - /// await client.Endpoints.Params.UploadWithPathAsync( - /// "upload-path", - /// new MemoryStream(Encoding.UTF8.GetBytes("[bytes]")) - /// ); - /// public WithRawResponseTask UploadWithPathAsync( string param, Stream request, diff --git a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/SeedExhaustive.csproj b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/SeedExhaustive.csproj index e2fc7bf743e9..3cdb5232e256 100644 --- a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/SeedExhaustive.csproj +++ b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/SeedExhaustive.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/exhaustive/fern + https://github.com/exhaustive/fern + git true diff --git a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs index 55a62fded413..97a4aa9f4f38 100644 --- a/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs +++ b/seed/csharp-sdk/exhaustive/include-exception-handler/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs @@ -26,11 +26,11 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - *: Can interfere with comment blocks /// - /**: JSDoc comment start /// - ** /: JSDoc comment end - /// - &: HTML entities + /// - &: HTML entities /// /// XMLDoc (C#): /// - <: >: XML tags - /// - &: ': ": <: >: XML special characters + /// - &: ': ": <: >: XML special characters /// - {: }: Used for interpolated strings /// - ///: Comment marker /// - /**: Block comment start @@ -44,7 +44,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// Javadoc (Java): /// - @: Used for Javadoc tags /// - <: >: HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - *: Can interfere with comment blocks /// - /**: Javadoc comment start /// - ** /: Javadoc comment end @@ -53,7 +53,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - \: Used for Doxygen commands /// - @: Alternative command prefix /// - <: >: XML/HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - /**: C-style comment start /// - ** /: C-style comment end /// @@ -76,7 +76,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - /**: PHPDoc comment start /// - ** /: PHPDoc comment end /// - *: Can interfere with comment blocks - /// - &: HTML entities + /// - &: HTML entities /// [JsonPropertyName("string")] public required string String { get; set; } diff --git a/seed/csharp-sdk/exhaustive/no-generate-error-types/README.md b/seed/csharp-sdk/exhaustive/no-generate-error-types/README.md index 016292ae33f6..d7acfee9e59e 100644 --- a/seed/csharp-sdk/exhaustive/no-generate-error-types/README.md +++ b/seed/csharp-sdk/exhaustive/no-generate-error-types/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -124,7 +127,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -137,7 +140,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -167,7 +170,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); +var parsedData = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive.Test/Utils/OptionalComparer.cs index 6cd4f6753570..33194e3dfece 100644 --- a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/Extensions.cs b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/Extensions.cs index 7a9af98fd1b0..5aa245a72e8d 100644 --- a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/Extensions.cs +++ b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/NullableAttribute.cs b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/NullableAttribute.cs index b7060ccecf98..22a72c62aafa 100644 --- a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedExhaustive.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedExhaustive.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/Optional.cs b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/Optional.cs index 40b24af7ff1d..eb807bfa6ccd 100644 --- a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/Optional.cs +++ b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/OptionalAttribute.cs b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/OptionalAttribute.cs index 8f18675316ca..d8c4c2081140 100644 --- a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedExhaustive.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/QueryStringBuilder.cs b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/QueryStringBuilder.cs index 7ac49dc02ab6..1d0579cb7848 100644 --- a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs index 3f5a7d616056..f0f4cbc07e60 100644 --- a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs +++ b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs @@ -1154,12 +1154,6 @@ public WithRawResponseTask ModifyWithInlinePathAsync( /// /// POST bytes with path param returning object /// - /// - /// await client.Endpoints.Params.UploadWithPathAsync( - /// "upload-path", - /// new MemoryStream(Encoding.UTF8.GetBytes("[bytes]")) - /// ); - /// public WithRawResponseTask UploadWithPathAsync( string param, Stream request, diff --git a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/SeedExhaustive.csproj b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/SeedExhaustive.csproj index e2fc7bf743e9..3cdb5232e256 100644 --- a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/SeedExhaustive.csproj +++ b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/SeedExhaustive.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/exhaustive/fern + https://github.com/exhaustive/fern + git true diff --git a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs index 55a62fded413..97a4aa9f4f38 100644 --- a/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs +++ b/seed/csharp-sdk/exhaustive/no-generate-error-types/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs @@ -26,11 +26,11 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - *: Can interfere with comment blocks /// - /**: JSDoc comment start /// - ** /: JSDoc comment end - /// - &: HTML entities + /// - &: HTML entities /// /// XMLDoc (C#): /// - <: >: XML tags - /// - &: ': ": <: >: XML special characters + /// - &: ': ": <: >: XML special characters /// - {: }: Used for interpolated strings /// - ///: Comment marker /// - /**: Block comment start @@ -44,7 +44,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// Javadoc (Java): /// - @: Used for Javadoc tags /// - <: >: HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - *: Can interfere with comment blocks /// - /**: Javadoc comment start /// - ** /: Javadoc comment end @@ -53,7 +53,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - \: Used for Doxygen commands /// - @: Alternative command prefix /// - <: >: XML/HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - /**: C-style comment start /// - ** /: C-style comment end /// @@ -76,7 +76,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - /**: PHPDoc comment start /// - ** /: PHPDoc comment end /// - *: Can interfere with comment blocks - /// - &: HTML entities + /// - &: HTML entities /// [JsonPropertyName("string")] public required string String { get; set; } diff --git a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/README.md b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/README.md index 016292ae33f6..d7acfee9e59e 100644 --- a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/README.md +++ b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -124,7 +127,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -137,7 +140,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -167,7 +170,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); +var parsedData = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive.Test/Utils/OptionalComparer.cs index 6cd4f6753570..33194e3dfece 100644 --- a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/Extensions.cs b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/Extensions.cs index 7a9af98fd1b0..5aa245a72e8d 100644 --- a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/Extensions.cs +++ b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/NullableAttribute.cs b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/NullableAttribute.cs index b7060ccecf98..22a72c62aafa 100644 --- a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedExhaustive.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedExhaustive.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/Optional.cs b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/Optional.cs index 40b24af7ff1d..eb807bfa6ccd 100644 --- a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/Optional.cs +++ b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/OptionalAttribute.cs b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/OptionalAttribute.cs index 8f18675316ca..d8c4c2081140 100644 --- a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedExhaustive.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/QueryStringBuilder.cs b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/QueryStringBuilder.cs index 7ac49dc02ab6..1d0579cb7848 100644 --- a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs index 5ac846d8e8e3..4ad59c539646 100644 --- a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs +++ b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs @@ -1176,12 +1176,6 @@ public WithRawResponseTask ModifyWithInlinePathAsync( /// /// POST bytes with path param returning object /// - /// - /// await client.Endpoints.Params.UploadWithPathAsync( - /// "upload-path", - /// new MemoryStream(Encoding.UTF8.GetBytes("[bytes]")) - /// ); - /// public WithRawResponseTask UploadWithPathAsync( string param, Stream request, diff --git a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/SeedExhaustive.csproj b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/SeedExhaustive.csproj index e2fc7bf743e9..3cdb5232e256 100644 --- a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/SeedExhaustive.csproj +++ b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/SeedExhaustive.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/exhaustive/fern + https://github.com/exhaustive/fern + git true diff --git a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs index 55a62fded413..97a4aa9f4f38 100644 --- a/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs +++ b/seed/csharp-sdk/exhaustive/no-root-namespace-for-core-classes/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs @@ -26,11 +26,11 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - *: Can interfere with comment blocks /// - /**: JSDoc comment start /// - ** /: JSDoc comment end - /// - &: HTML entities + /// - &: HTML entities /// /// XMLDoc (C#): /// - <: >: XML tags - /// - &: ': ": <: >: XML special characters + /// - &: ': ": <: >: XML special characters /// - {: }: Used for interpolated strings /// - ///: Comment marker /// - /**: Block comment start @@ -44,7 +44,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// Javadoc (Java): /// - @: Used for Javadoc tags /// - <: >: HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - *: Can interfere with comment blocks /// - /**: Javadoc comment start /// - ** /: Javadoc comment end @@ -53,7 +53,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - \: Used for Doxygen commands /// - @: Alternative command prefix /// - <: >: XML/HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - /**: C-style comment start /// - ** /: C-style comment end /// @@ -76,7 +76,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - /**: PHPDoc comment start /// - ** /: PHPDoc comment end /// - *: Can interfere with comment blocks - /// - &: HTML entities + /// - &: HTML entities /// [JsonPropertyName("string")] public required string String { get; set; } diff --git a/seed/csharp-sdk/exhaustive/oidc-token/README.md b/seed/csharp-sdk/exhaustive/oidc-token/README.md index 6dd5a4810d6a..8dd0574f7177 100644 --- a/seed/csharp-sdk/exhaustive/oidc-token/README.md +++ b/seed/csharp-sdk/exhaustive/oidc-token/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -124,7 +127,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -137,7 +140,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -167,7 +170,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); +var parsedData = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive.Test/Utils/OptionalComparer.cs index 6cd4f6753570..33194e3dfece 100644 --- a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/Extensions.cs b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/Extensions.cs index 7a9af98fd1b0..5aa245a72e8d 100644 --- a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/Extensions.cs +++ b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/NullableAttribute.cs b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/NullableAttribute.cs index b7060ccecf98..22a72c62aafa 100644 --- a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedExhaustive.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedExhaustive.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/Optional.cs b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/Optional.cs index 40b24af7ff1d..eb807bfa6ccd 100644 --- a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/Optional.cs +++ b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/OptionalAttribute.cs b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/OptionalAttribute.cs index 8f18675316ca..d8c4c2081140 100644 --- a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedExhaustive.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/QueryStringBuilder.cs b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/QueryStringBuilder.cs index 7ac49dc02ab6..1d0579cb7848 100644 --- a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs index 5ac846d8e8e3..4ad59c539646 100644 --- a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs +++ b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs @@ -1176,12 +1176,6 @@ public WithRawResponseTask ModifyWithInlinePathAsync( /// /// POST bytes with path param returning object /// - /// - /// await client.Endpoints.Params.UploadWithPathAsync( - /// "upload-path", - /// new MemoryStream(Encoding.UTF8.GetBytes("[bytes]")) - /// ); - /// public WithRawResponseTask UploadWithPathAsync( string param, Stream request, diff --git a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/SeedExhaustive.csproj b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/SeedExhaustive.csproj index e2fc7bf743e9..3cdb5232e256 100644 --- a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/SeedExhaustive.csproj +++ b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/SeedExhaustive.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/exhaustive/fern + https://github.com/exhaustive/fern + git true diff --git a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs index 55a62fded413..97a4aa9f4f38 100644 --- a/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs +++ b/seed/csharp-sdk/exhaustive/oidc-token/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs @@ -26,11 +26,11 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - *: Can interfere with comment blocks /// - /**: JSDoc comment start /// - ** /: JSDoc comment end - /// - &: HTML entities + /// - &: HTML entities /// /// XMLDoc (C#): /// - <: >: XML tags - /// - &: ': ": <: >: XML special characters + /// - &: ': ": <: >: XML special characters /// - {: }: Used for interpolated strings /// - ///: Comment marker /// - /**: Block comment start @@ -44,7 +44,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// Javadoc (Java): /// - @: Used for Javadoc tags /// - <: >: HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - *: Can interfere with comment blocks /// - /**: Javadoc comment start /// - ** /: Javadoc comment end @@ -53,7 +53,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - \: Used for Doxygen commands /// - @: Alternative command prefix /// - <: >: XML/HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - /**: C-style comment start /// - ** /: C-style comment end /// @@ -76,7 +76,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - /**: PHPDoc comment start /// - ** /: PHPDoc comment end /// - *: Can interfere with comment blocks - /// - &: HTML entities + /// - &: HTML entities /// [JsonPropertyName("string")] public required string String { get; set; } diff --git a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/README.md b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/README.md index 016292ae33f6..d7acfee9e59e 100644 --- a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/README.md +++ b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -124,7 +127,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -137,7 +140,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -167,7 +170,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); +var parsedData = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive.Test/Utils/OptionalComparer.cs index 6cd4f6753570..33194e3dfece 100644 --- a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/Extensions.cs b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/Extensions.cs index 7a9af98fd1b0..5aa245a72e8d 100644 --- a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/Extensions.cs +++ b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/NullableAttribute.cs b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/NullableAttribute.cs index b7060ccecf98..22a72c62aafa 100644 --- a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedExhaustive.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedExhaustive.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/Optional.cs b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/Optional.cs index 40b24af7ff1d..eb807bfa6ccd 100644 --- a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/Optional.cs +++ b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/OptionalAttribute.cs b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/OptionalAttribute.cs index 8f18675316ca..d8c4c2081140 100644 --- a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedExhaustive.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/QueryStringBuilder.cs b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/QueryStringBuilder.cs index 7ac49dc02ab6..1d0579cb7848 100644 --- a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs index 0632d1f92a03..d18e7e5c6bd3 100644 --- a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs +++ b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs @@ -1176,12 +1176,6 @@ public WithRawResponseTask ModifyWithInlinePathAsync( /// /// POST bytes with path param returning object /// - /// - /// await client.Endpoints.Params.UploadWithPathAsync( - /// "upload-path", - /// new MemoryStream(Encoding.UTF8.GetBytes("[bytes]")) - /// ); - /// public WithRawResponseTask UploadWithPathAsync( string param, Stream request, diff --git a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/SeedExhaustive.csproj b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/SeedExhaustive.csproj index e2fc7bf743e9..3cdb5232e256 100644 --- a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/SeedExhaustive.csproj +++ b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/SeedExhaustive.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/exhaustive/fern + https://github.com/exhaustive/fern + git true diff --git a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs index 55a62fded413..97a4aa9f4f38 100644 --- a/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs +++ b/seed/csharp-sdk/exhaustive/redact-response-body-on-error/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs @@ -26,11 +26,11 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - *: Can interfere with comment blocks /// - /**: JSDoc comment start /// - ** /: JSDoc comment end - /// - &: HTML entities + /// - &: HTML entities /// /// XMLDoc (C#): /// - <: >: XML tags - /// - &: ': ": <: >: XML special characters + /// - &: ': ": <: >: XML special characters /// - {: }: Used for interpolated strings /// - ///: Comment marker /// - /**: Block comment start @@ -44,7 +44,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// Javadoc (Java): /// - @: Used for Javadoc tags /// - <: >: HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - *: Can interfere with comment blocks /// - /**: Javadoc comment start /// - ** /: Javadoc comment end @@ -53,7 +53,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - \: Used for Doxygen commands /// - @: Alternative command prefix /// - <: >: XML/HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - /**: C-style comment start /// - ** /: C-style comment end /// @@ -76,7 +76,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - /**: PHPDoc comment start /// - ** /: PHPDoc comment end /// - *: Can interfere with comment blocks - /// - &: HTML entities + /// - &: HTML entities /// [JsonPropertyName("string")] public required string String { get; set; } diff --git a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/README.md b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/README.md index 016292ae33f6..d7acfee9e59e 100644 --- a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/README.md +++ b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -124,7 +127,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -137,7 +140,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -167,7 +170,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); +var parsedData = await client.Endpoints.Container.GetAndReturnListOfPrimitivesAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/Extensions.cs b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/Extensions.cs index 7a9af98fd1b0..5aa245a72e8d 100644 --- a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/Extensions.cs +++ b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/NullableAttribute.cs b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/NullableAttribute.cs index b7060ccecf98..22a72c62aafa 100644 --- a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedExhaustive.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedExhaustive.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/Optional.cs b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/Optional.cs index 40b24af7ff1d..eb807bfa6ccd 100644 --- a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/Optional.cs +++ b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/OptionalAttribute.cs b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/OptionalAttribute.cs index 8f18675316ca..d8c4c2081140 100644 --- a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedExhaustive.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/QueryStringBuilder.cs b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/QueryStringBuilder.cs index 7ac49dc02ab6..1d0579cb7848 100644 --- a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs index 5ac846d8e8e3..4ad59c539646 100644 --- a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs +++ b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Endpoints/Params/ParamsClient.cs @@ -1176,12 +1176,6 @@ public WithRawResponseTask ModifyWithInlinePathAsync( /// /// POST bytes with path param returning object /// - /// - /// await client.Endpoints.Params.UploadWithPathAsync( - /// "upload-path", - /// new MemoryStream(Encoding.UTF8.GetBytes("[bytes]")) - /// ); - /// public WithRawResponseTask UploadWithPathAsync( string param, Stream request, diff --git a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/SeedExhaustive.csproj b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/SeedExhaustive.csproj index 1022f238cab6..a337749d5c10 100644 --- a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/SeedExhaustive.csproj +++ b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/SeedExhaustive.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/exhaustive/fern + https://github.com/exhaustive/fern + git true diff --git a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs index 55a62fded413..97a4aa9f4f38 100644 --- a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs +++ b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Types/Docs/Types/ObjectWithDocs.cs @@ -26,11 +26,11 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - *: Can interfere with comment blocks /// - /**: JSDoc comment start /// - ** /: JSDoc comment end - /// - &: HTML entities + /// - &: HTML entities /// /// XMLDoc (C#): /// - <: >: XML tags - /// - &: ': ": <: >: XML special characters + /// - &: ': ": <: >: XML special characters /// - {: }: Used for interpolated strings /// - ///: Comment marker /// - /**: Block comment start @@ -44,7 +44,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// Javadoc (Java): /// - @: Used for Javadoc tags /// - <: >: HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - *: Can interfere with comment blocks /// - /**: Javadoc comment start /// - ** /: Javadoc comment end @@ -53,7 +53,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - \: Used for Doxygen commands /// - @: Alternative command prefix /// - <: >: XML/HTML tags - /// - &: HTML entities + /// - &: HTML entities /// - /**: C-style comment start /// - ** /: C-style comment end /// @@ -76,7 +76,7 @@ public record ObjectWithDocs : IJsonOnDeserialized /// - /**: PHPDoc comment start /// - ** /: PHPDoc comment end /// - *: Can interfere with comment blocks - /// - &: HTML entities + /// - &: HTML entities /// [JsonPropertyName("string")] public required string String { get; set; } diff --git a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Types/Union/Types/MixedType.cs b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Types/Union/Types/MixedType.cs index f538a25f90c1..edbefbe96a59 100644 --- a/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Types/Union/Types/MixedType.cs +++ b/seed/csharp-sdk/exhaustive/use-undiscriminated-unions/src/SeedExhaustive/Types/Union/Types/MixedType.cs @@ -31,22 +31,22 @@ private MixedType(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a double value. + /// Factory method to create a union from a value. /// public static MixedType FromDouble(double value) => new("double", value); /// - /// Factory method to create a union from a bool value. + /// Factory method to create a union from a value. /// public static MixedType FromBool(bool value) => new("bool", value); /// - /// Factory method to create a union from a string value. + /// Factory method to create a union from a value. /// public static MixedType FromString(string value) => new("string", value); /// - /// Factory method to create a union from a IEnumerable value. + /// Factory method to create a union from a value. /// public static MixedType FromListOfString(IEnumerable value) => new("list", value); @@ -96,7 +96,7 @@ public string AsString() => : throw new SeedExhaustiveException("Union type is not 'string'"); /// - /// Returns the value as a if is 'list', otherwise throws an exception. + /// Returns the value as a if is 'list', otherwise throws an exception. /// /// Thrown when is not 'list'. public IEnumerable AsListOfString() => @@ -147,7 +147,7 @@ public bool TryGetString(out string? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetListOfString(out IEnumerable? value) { diff --git a/seed/csharp-sdk/extends/README.md b/seed/csharp-sdk/extends/README.md index 08c006dba316..0845f6c0f79d 100644 --- a/seed/csharp-sdk/extends/README.md +++ b/seed/csharp-sdk/extends/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -108,7 +111,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.ExtendedInlineRequestBodyAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -121,7 +124,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.ExtendedInlineRequestBodyAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -151,7 +154,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.ExtendedInlineRequestBodyAsync(...); +var parsedData = await client.ExtendedInlineRequestBodyAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/extends/src/SeedExtends.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/extends/src/SeedExtends.Test/Utils/OptionalComparer.cs index 46df36ff0702..54fecc6ba287 100644 --- a/seed/csharp-sdk/extends/src/SeedExtends.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/extends/src/SeedExtends.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/extends/src/SeedExtends/Core/Extensions.cs b/seed/csharp-sdk/extends/src/SeedExtends/Core/Extensions.cs index 8f3fcc362f53..e8c53f458815 100644 --- a/seed/csharp-sdk/extends/src/SeedExtends/Core/Extensions.cs +++ b/seed/csharp-sdk/extends/src/SeedExtends/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/extends/src/SeedExtends/Core/NullableAttribute.cs b/seed/csharp-sdk/extends/src/SeedExtends/Core/NullableAttribute.cs index 3c05c88016ce..3b2f91f79f21 100644 --- a/seed/csharp-sdk/extends/src/SeedExtends/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/extends/src/SeedExtends/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedExtends.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedExtends.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/extends/src/SeedExtends/Core/Optional.cs b/seed/csharp-sdk/extends/src/SeedExtends/Core/Optional.cs index 1f461e7d7326..11d32464dbd3 100644 --- a/seed/csharp-sdk/extends/src/SeedExtends/Core/Optional.cs +++ b/seed/csharp-sdk/extends/src/SeedExtends/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/extends/src/SeedExtends/Core/OptionalAttribute.cs b/seed/csharp-sdk/extends/src/SeedExtends/Core/OptionalAttribute.cs index 63d97f1ee831..651eb145a4e0 100644 --- a/seed/csharp-sdk/extends/src/SeedExtends/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/extends/src/SeedExtends/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedExtends.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/extends/src/SeedExtends/Core/QueryStringBuilder.cs b/seed/csharp-sdk/extends/src/SeedExtends/Core/QueryStringBuilder.cs index af454a1afcdf..c1ec41c97e3b 100644 --- a/seed/csharp-sdk/extends/src/SeedExtends/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/extends/src/SeedExtends/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/extends/src/SeedExtends/SeedExtends.csproj b/seed/csharp-sdk/extends/src/SeedExtends/SeedExtends.csproj index 60f17e298892..9862ec89e3a5 100644 --- a/seed/csharp-sdk/extends/src/SeedExtends/SeedExtends.csproj +++ b/seed/csharp-sdk/extends/src/SeedExtends/SeedExtends.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/extends/fern + https://github.com/extends/fern + git true diff --git a/seed/csharp-sdk/extra-properties/README.md b/seed/csharp-sdk/extra-properties/README.md index e1b69b8ace7a..45169a72bbe2 100644 --- a/seed/csharp-sdk/extra-properties/README.md +++ b/seed/csharp-sdk/extra-properties/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -113,7 +116,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -126,7 +129,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -156,7 +159,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.CreateUserAsync(...); +var parsedData = await client.User.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties.Test/Utils/OptionalComparer.cs index fb5a17962b8d..c741c4766c82 100644 --- a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/Extensions.cs b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/Extensions.cs index 42f888cc05df..2fb365be249c 100644 --- a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/Extensions.cs +++ b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/NullableAttribute.cs b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/NullableAttribute.cs index 9172d7fa421f..54243e910724 100644 --- a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedExtraProperties.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedExtraProperties.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/Optional.cs b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/Optional.cs index 38e42e50a321..516478cb2141 100644 --- a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/Optional.cs +++ b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/OptionalAttribute.cs b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/OptionalAttribute.cs index 1397f12c6eac..10db82fcdb7d 100644 --- a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedExtraProperties.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/QueryStringBuilder.cs b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/QueryStringBuilder.cs index e2054e57a0b5..9ece5cbfced4 100644 --- a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/SeedExtraProperties.csproj b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/SeedExtraProperties.csproj index 2c7f36c251b1..0c6ac1c97aa0 100644 --- a/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/SeedExtraProperties.csproj +++ b/seed/csharp-sdk/extra-properties/src/SeedExtraProperties/SeedExtraProperties.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/extra-properties/fern + https://github.com/extra-properties/fern + git true diff --git a/seed/csharp-sdk/file-download/README.md b/seed/csharp-sdk/file-download/README.md index dc42b8d35133..618819871ec4 100644 --- a/seed/csharp-sdk/file-download/README.md +++ b/seed/csharp-sdk/file-download/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.SimpleAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.SimpleAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.SimpleAsync(...); +var parsedData = await client.Service.SimpleAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/file-download/src/SeedFileDownload.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/file-download/src/SeedFileDownload.Test/Utils/OptionalComparer.cs index d6c918878f1c..9db9667b8774 100644 --- a/seed/csharp-sdk/file-download/src/SeedFileDownload.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/file-download/src/SeedFileDownload.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/Extensions.cs b/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/Extensions.cs index 2eb454b11ae5..3d25f80aebdf 100644 --- a/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/Extensions.cs +++ b/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/NullableAttribute.cs b/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/NullableAttribute.cs index b39bf2903a8c..264d54186875 100644 --- a/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedFileDownload.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedFileDownload.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/Optional.cs b/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/Optional.cs index 465107bb50c5..43b246f96ed9 100644 --- a/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/Optional.cs +++ b/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/OptionalAttribute.cs b/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/OptionalAttribute.cs index 0336f69ff8cb..8bcba26f0e90 100644 --- a/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedFileDownload.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/QueryStringBuilder.cs b/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/QueryStringBuilder.cs index bfb0b6f64e83..952a0d10fb7b 100644 --- a/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/file-download/src/SeedFileDownload/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/file-download/src/SeedFileDownload/SeedFileDownload.csproj b/seed/csharp-sdk/file-download/src/SeedFileDownload/SeedFileDownload.csproj index 138bb7fd6f9c..77b52775019e 100644 --- a/seed/csharp-sdk/file-download/src/SeedFileDownload/SeedFileDownload.csproj +++ b/seed/csharp-sdk/file-download/src/SeedFileDownload/SeedFileDownload.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/file-download/fern + https://github.com/file-download/fern + git true diff --git a/seed/csharp-sdk/file-upload-openapi/README.md b/seed/csharp-sdk/file-upload-openapi/README.md index 7e1858cf2eb9..3409a5105a63 100644 --- a/seed/csharp-sdk/file-upload-openapi/README.md +++ b/seed/csharp-sdk/file-upload-openapi/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.FileUploadExample.UploadFileAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.FileUploadExample.UploadFileAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.FileUploadExample.UploadFileAsync(...); +var parsedData = await client.FileUploadExample.UploadFileAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/file-upload-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/file-upload-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/file-upload-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/file-upload-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/file-upload-openapi/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/file-upload-openapi/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/file-upload-openapi/src/SeedApi/SeedApi.csproj index 3d663597fd73..07643314440f 100644 --- a/seed/csharp-sdk/file-upload-openapi/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/file-upload-openapi/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/file-upload-openapi/fern + https://github.com/file-upload-openapi/fern + git true diff --git a/seed/csharp-sdk/file-upload/README.md b/seed/csharp-sdk/file-upload/README.md index 74d06ef1e773..e2f271635570 100644 --- a/seed/csharp-sdk/file-upload/README.md +++ b/seed/csharp-sdk/file-upload/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -102,7 +105,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.JustFileAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -115,7 +118,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.JustFileAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -145,7 +148,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.JustFileAsync(...); +var parsedData = await client.Service.JustFileAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/file-upload/src/SeedFileUpload.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/file-upload/src/SeedFileUpload.Test/Utils/OptionalComparer.cs index e6d31b816547..96511648af19 100644 --- a/seed/csharp-sdk/file-upload/src/SeedFileUpload.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/file-upload/src/SeedFileUpload.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/Extensions.cs b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/Extensions.cs index 7d9f82e81c45..cd7a2ca8ee04 100644 --- a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/Extensions.cs +++ b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/NullableAttribute.cs b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/NullableAttribute.cs index f0da1c153e96..a2d1ee3358e6 100644 --- a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedFileUpload.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedFileUpload.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/Optional.cs b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/Optional.cs index a710c14d5f96..9de7ca433117 100644 --- a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/Optional.cs +++ b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/OptionalAttribute.cs b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/OptionalAttribute.cs index 7b818aa7afae..0ca75ec5a47c 100644 --- a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedFileUpload.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/QueryStringBuilder.cs b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/QueryStringBuilder.cs index d84fe0d7f3e7..932590b17c35 100644 --- a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/file-upload/src/SeedFileUpload/SeedFileUpload.csproj b/seed/csharp-sdk/file-upload/src/SeedFileUpload/SeedFileUpload.csproj index 3fee2045eba0..3b40135412fd 100644 --- a/seed/csharp-sdk/file-upload/src/SeedFileUpload/SeedFileUpload.csproj +++ b/seed/csharp-sdk/file-upload/src/SeedFileUpload/SeedFileUpload.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/file-upload/fern + https://github.com/file-upload/fern + git true diff --git a/seed/csharp-sdk/folders/README.md b/seed/csharp-sdk/folders/README.md index b651ec141267..33cd267b6274 100644 --- a/seed/csharp-sdk/folders/README.md +++ b/seed/csharp-sdk/folders/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.FooAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.FooAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.FooAsync(...); +var parsedData = await client.FooAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/folders/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/folders/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/folders/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/folders/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/folders/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/folders/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/folders/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/folders/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/folders/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/folders/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/folders/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/folders/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/folders/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/folders/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/folders/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/folders/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/folders/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/folders/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/folders/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/folders/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/folders/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/folders/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/folders/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/folders/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/folders/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/folders/src/SeedApi/SeedApi.csproj index cd05ab977685..33cac28abd2e 100644 --- a/seed/csharp-sdk/folders/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/folders/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/folders/fern + https://github.com/folders/fern + git true diff --git a/seed/csharp-sdk/header-auth-environment-variable/README.md b/seed/csharp-sdk/header-auth-environment-variable/README.md index adf871cb5660..7a40001d7c24 100644 --- a/seed/csharp-sdk/header-auth-environment-variable/README.md +++ b/seed/csharp-sdk/header-auth-environment-variable/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.GetWithBearerTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.GetWithBearerTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.GetWithBearerTokenAsync(...); +var parsedData = await client.Service.GetWithBearerTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs index 8d5be376abf8..fc7b5b19b9d9 100644 --- a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/Extensions.cs b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/Extensions.cs index e223edb96651..ec8d89ac3be1 100644 --- a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/Extensions.cs +++ b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/NullableAttribute.cs b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/NullableAttribute.cs index 31515abfcc4b..04e7f9bbe7fc 100644 --- a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedHeaderTokenEnvironmentVariable.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedHeaderTokenEnvironmentVariable.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/Optional.cs b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/Optional.cs index ca416aee5f51..9f6b7bd56717 100644 --- a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/Optional.cs +++ b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/OptionalAttribute.cs b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/OptionalAttribute.cs index d42b7f5ad164..9b516af90ba1 100644 --- a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedHeaderTokenEnvironmentVariable.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/QueryStringBuilder.cs b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/QueryStringBuilder.cs index 25f4e8e31b81..b61d00e98028 100644 --- a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/SeedHeaderTokenEnvironmentVariable.csproj b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/SeedHeaderTokenEnvironmentVariable.csproj index 2483de32ccc7..5b086da42580 100644 --- a/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/SeedHeaderTokenEnvironmentVariable.csproj +++ b/seed/csharp-sdk/header-auth-environment-variable/src/SeedHeaderTokenEnvironmentVariable/SeedHeaderTokenEnvironmentVariable.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/header-auth-environment-variable/fern + https://github.com/header-auth-environment-variable/fern + git true diff --git a/seed/csharp-sdk/header-auth/README.md b/seed/csharp-sdk/header-auth/README.md index bda78019cac1..d2c1a1d620b5 100644 --- a/seed/csharp-sdk/header-auth/README.md +++ b/seed/csharp-sdk/header-auth/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.GetWithBearerTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.GetWithBearerTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.GetWithBearerTokenAsync(...); +var parsedData = await client.Service.GetWithBearerTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/header-auth/src/SeedHeaderToken.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/header-auth/src/SeedHeaderToken.Test/Utils/OptionalComparer.cs index 9a151f34e4c3..ec3f9d6a9ab1 100644 --- a/seed/csharp-sdk/header-auth/src/SeedHeaderToken.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/header-auth/src/SeedHeaderToken.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/Extensions.cs b/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/Extensions.cs index f8852aab8c16..7c91f2c0f5f2 100644 --- a/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/Extensions.cs +++ b/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/NullableAttribute.cs b/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/NullableAttribute.cs index 3e6b6cde3625..0e3a3db11875 100644 --- a/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedHeaderToken.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedHeaderToken.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/Optional.cs b/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/Optional.cs index 05ccb13be855..db8c6dc6b455 100644 --- a/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/Optional.cs +++ b/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/OptionalAttribute.cs b/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/OptionalAttribute.cs index f95570976ff3..e692ef73fca9 100644 --- a/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedHeaderToken.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/QueryStringBuilder.cs b/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/QueryStringBuilder.cs index 0d0b8362e001..7d56a608bf2c 100644 --- a/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/header-auth/src/SeedHeaderToken/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/header-auth/src/SeedHeaderToken/SeedHeaderToken.csproj b/seed/csharp-sdk/header-auth/src/SeedHeaderToken/SeedHeaderToken.csproj index 71bbe767730b..3132f0695dd5 100644 --- a/seed/csharp-sdk/header-auth/src/SeedHeaderToken/SeedHeaderToken.csproj +++ b/seed/csharp-sdk/header-auth/src/SeedHeaderToken/SeedHeaderToken.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/header-auth/fern + https://github.com/header-auth/fern + git true diff --git a/seed/csharp-sdk/http-head/README.md b/seed/csharp-sdk/http-head/README.md index 6c334de0a850..9f69d4831acc 100644 --- a/seed/csharp-sdk/http-head/README.md +++ b/seed/csharp-sdk/http-head/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.HeadAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.HeadAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.HeadAsync(...); +var parsedData = await client.User.HeadAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/http-head/src/SeedHttpHead.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/http-head/src/SeedHttpHead.Test/Utils/OptionalComparer.cs index dcea31fd268c..321f0ff4b89c 100644 --- a/seed/csharp-sdk/http-head/src/SeedHttpHead.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/http-head/src/SeedHttpHead.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/Extensions.cs b/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/Extensions.cs index 06b0c209ae73..1cb35f83e28d 100644 --- a/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/Extensions.cs +++ b/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/NullableAttribute.cs b/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/NullableAttribute.cs index 55ea7ea1fa6a..2c2a0aaf37f4 100644 --- a/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedHttpHead.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedHttpHead.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/Optional.cs b/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/Optional.cs index 8e19231dc883..2b2f453c2fde 100644 --- a/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/Optional.cs +++ b/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/OptionalAttribute.cs b/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/OptionalAttribute.cs index 255ef6d97bb5..c4d109da2ead 100644 --- a/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedHttpHead.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/QueryStringBuilder.cs b/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/QueryStringBuilder.cs index 663d33e103c1..bc2ed5de26dd 100644 --- a/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/http-head/src/SeedHttpHead/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/http-head/src/SeedHttpHead/SeedHttpHead.csproj b/seed/csharp-sdk/http-head/src/SeedHttpHead/SeedHttpHead.csproj index 8bc3fa31d7f8..2f8172bc2312 100644 --- a/seed/csharp-sdk/http-head/src/SeedHttpHead/SeedHttpHead.csproj +++ b/seed/csharp-sdk/http-head/src/SeedHttpHead/SeedHttpHead.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/http-head/fern + https://github.com/http-head/fern + git true diff --git a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/README.md b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/README.md index 3158cb1d4c4c..b01bacef3e65 100644 --- a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/README.md +++ b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -102,7 +105,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Payment.CreateAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -115,7 +118,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Payment.CreateAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -145,7 +148,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Payment.CreateAsync(...); +var parsedData = await client.Payment.CreateAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders.Test/Utils/OptionalComparer.cs index fb945d43a7ba..1dd47b454ed9 100644 --- a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/Extensions.cs b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/Extensions.cs index 00df4448704e..8bc8257e092d 100644 --- a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/Extensions.cs +++ b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/NullableAttribute.cs b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/NullableAttribute.cs index 8fe4b390fb68..94ef8a88c79a 100644 --- a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedIdempotencyHeaders.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedIdempotencyHeaders.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/Optional.cs b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/Optional.cs index 23024f99fb75..e9d3d9af00a2 100644 --- a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/Optional.cs +++ b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/OptionalAttribute.cs b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/OptionalAttribute.cs index f5d527fba7e7..d580e8107df0 100644 --- a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedIdempotencyHeaders.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/QueryStringBuilder.cs b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/QueryStringBuilder.cs index ae00a5e2385c..0d4c2652ba81 100644 --- a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/SeedIdempotencyHeaders.csproj b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/SeedIdempotencyHeaders.csproj index 8123d6629705..ddb770c86005 100644 --- a/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/SeedIdempotencyHeaders.csproj +++ b/seed/csharp-sdk/idempotency-headers/auto-generate-idempotency-key/src/SeedIdempotencyHeaders/SeedIdempotencyHeaders.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/idempotency-headers/fern + https://github.com/idempotency-headers/fern + git true diff --git a/seed/csharp-sdk/idempotency-headers/no-custom-config/README.md b/seed/csharp-sdk/idempotency-headers/no-custom-config/README.md index 3158cb1d4c4c..b01bacef3e65 100644 --- a/seed/csharp-sdk/idempotency-headers/no-custom-config/README.md +++ b/seed/csharp-sdk/idempotency-headers/no-custom-config/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -102,7 +105,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Payment.CreateAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -115,7 +118,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Payment.CreateAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -145,7 +148,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Payment.CreateAsync(...); +var parsedData = await client.Payment.CreateAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders.Test/Utils/OptionalComparer.cs index fb945d43a7ba..1dd47b454ed9 100644 --- a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/Extensions.cs b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/Extensions.cs index 00df4448704e..8bc8257e092d 100644 --- a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/Extensions.cs +++ b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/NullableAttribute.cs b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/NullableAttribute.cs index 8fe4b390fb68..94ef8a88c79a 100644 --- a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedIdempotencyHeaders.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedIdempotencyHeaders.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/Optional.cs b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/Optional.cs index 23024f99fb75..e9d3d9af00a2 100644 --- a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/Optional.cs +++ b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/OptionalAttribute.cs b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/OptionalAttribute.cs index f5d527fba7e7..d580e8107df0 100644 --- a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedIdempotencyHeaders.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/QueryStringBuilder.cs b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/QueryStringBuilder.cs index ae00a5e2385c..0d4c2652ba81 100644 --- a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/SeedIdempotencyHeaders.csproj b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/SeedIdempotencyHeaders.csproj index 8123d6629705..ddb770c86005 100644 --- a/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/SeedIdempotencyHeaders.csproj +++ b/seed/csharp-sdk/idempotency-headers/no-custom-config/src/SeedIdempotencyHeaders/SeedIdempotencyHeaders.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/idempotency-headers/fern + https://github.com/idempotency-headers/fern + git true diff --git a/seed/csharp-sdk/imdb/allow-user-agent-app-info/.fern/metadata.json b/seed/csharp-sdk/imdb/allow-user-agent-app-info/.fern/metadata.json index 37411c43766f..a19d1d7d86f8 100644 --- a/seed/csharp-sdk/imdb/allow-user-agent-app-info/.fern/metadata.json +++ b/seed/csharp-sdk/imdb/allow-user-agent-app-info/.fern/metadata.json @@ -7,8 +7,7 @@ "allow-user-agent-app-info": true }, "originGitCommit": "DUMMY", - "invokedBy": "ci", + "invokedBy": "manual", "requestedVersion": "0.0.1", - "ciProvider": "github", "sdkVersion": "0.0.1" -} +} \ No newline at end of file diff --git a/seed/csharp-sdk/imdb/allow-user-agent-app-info/README.md b/seed/csharp-sdk/imdb/allow-user-agent-app-info/README.md index 946935a0b7a2..573e3905d500 100644 --- a/seed/csharp-sdk/imdb/allow-user-agent-app-info/README.md +++ b/seed/csharp-sdk/imdb/allow-user-agent-app-info/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Imdb.CreateMovieAsync(...); +var parsedData = await client.Imdb.CreateMovieAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/SeedApi.csproj index 2370426e8f7b..a94d2d234989 100644 --- a/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/imdb/allow-user-agent-app-info/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/imdb/fern + https://github.com/imdb/fern + git true diff --git a/seed/csharp-sdk/imdb/exception-class-names/README.md b/seed/csharp-sdk/imdb/exception-class-names/README.md index a7084ec4b346..235623ef8f6a 100644 --- a/seed/csharp-sdk/imdb/exception-class-names/README.md +++ b/seed/csharp-sdk/imdb/exception-class-names/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Imdb.CreateMovieAsync(...); +var parsedData = await client.Imdb.CreateMovieAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/SeedApi.csproj index bebfefd11aa1..d6b337a69973 100644 --- a/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/imdb/exception-class-names/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/imdb/fern + https://github.com/imdb/fern + git true diff --git a/seed/csharp-sdk/imdb/exported-client-class-name/README.md b/seed/csharp-sdk/imdb/exported-client-class-name/README.md index 2629f4d3380a..daa6bf1e5976 100644 --- a/seed/csharp-sdk/imdb/exported-client-class-name/README.md +++ b/seed/csharp-sdk/imdb/exported-client-class-name/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Imdb.CreateMovieAsync(...); +var parsedData = await client.Imdb.CreateMovieAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/SeedApi.csproj index bebfefd11aa1..d6b337a69973 100644 --- a/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/imdb/exported-client-class-name/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/imdb/fern + https://github.com/imdb/fern + git true diff --git a/seed/csharp-sdk/imdb/extra-dependencies-override/README.md b/seed/csharp-sdk/imdb/extra-dependencies-override/README.md index 946935a0b7a2..573e3905d500 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies-override/README.md +++ b/seed/csharp-sdk/imdb/extra-dependencies-override/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Imdb.CreateMovieAsync(...); +var parsedData = await client.Imdb.CreateMovieAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/SeedApi.csproj index 3fed3420f6a8..f1ad380cda90 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/imdb/extra-dependencies-override/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/imdb/fern + https://github.com/imdb/fern + git true diff --git a/seed/csharp-sdk/imdb/extra-dependencies/README.md b/seed/csharp-sdk/imdb/extra-dependencies/README.md index 946935a0b7a2..573e3905d500 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies/README.md +++ b/seed/csharp-sdk/imdb/extra-dependencies/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Imdb.CreateMovieAsync(...); +var parsedData = await client.Imdb.CreateMovieAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/SeedApi.csproj index 00cba0adb4c4..83e61064d5d3 100644 --- a/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/imdb/extra-dependencies/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/imdb/fern + https://github.com/imdb/fern + git true diff --git a/seed/csharp-sdk/imdb/include-exception-handler/README.md b/seed/csharp-sdk/imdb/include-exception-handler/README.md index 946935a0b7a2..573e3905d500 100644 --- a/seed/csharp-sdk/imdb/include-exception-handler/README.md +++ b/seed/csharp-sdk/imdb/include-exception-handler/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Imdb.CreateMovieAsync(...); +var parsedData = await client.Imdb.CreateMovieAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/SeedApi.csproj index bebfefd11aa1..d6b337a69973 100644 --- a/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/imdb/include-exception-handler/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/imdb/fern + https://github.com/imdb/fern + git true diff --git a/seed/csharp-sdk/imdb/include-platform-headers/README.md b/seed/csharp-sdk/imdb/include-platform-headers/README.md index 946935a0b7a2..573e3905d500 100644 --- a/seed/csharp-sdk/imdb/include-platform-headers/README.md +++ b/seed/csharp-sdk/imdb/include-platform-headers/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Imdb.CreateMovieAsync(...); +var parsedData = await client.Imdb.CreateMovieAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/SeedApi.csproj index 2370426e8f7b..a94d2d234989 100644 --- a/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/imdb/include-platform-headers/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/imdb/fern + https://github.com/imdb/fern + git true diff --git a/seed/csharp-sdk/imdb/no-custom-config/README.md b/seed/csharp-sdk/imdb/no-custom-config/README.md index 946935a0b7a2..573e3905d500 100644 --- a/seed/csharp-sdk/imdb/no-custom-config/README.md +++ b/seed/csharp-sdk/imdb/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Imdb.CreateMovieAsync(...); +var parsedData = await client.Imdb.CreateMovieAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/SeedApi.csproj index bebfefd11aa1..d6b337a69973 100644 --- a/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/imdb/no-custom-config/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/imdb/fern + https://github.com/imdb/fern + git true diff --git a/seed/csharp-sdk/imdb/omit-fern-headers/README.md b/seed/csharp-sdk/imdb/omit-fern-headers/README.md index 946935a0b7a2..573e3905d500 100644 --- a/seed/csharp-sdk/imdb/omit-fern-headers/README.md +++ b/seed/csharp-sdk/imdb/omit-fern-headers/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Imdb.CreateMovieAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Imdb.CreateMovieAsync(...); +var parsedData = await client.Imdb.CreateMovieAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/SeedApi.csproj index bebfefd11aa1..d6b337a69973 100644 --- a/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/imdb/omit-fern-headers/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/imdb/fern + https://github.com/imdb/fern + git true diff --git a/seed/csharp-sdk/inferred-auth-explicit/README.md b/seed/csharp-sdk/inferred-auth-explicit/README.md index 18315d465a5c..4a37bc0c16fb 100644 --- a/seed/csharp-sdk/inferred-auth-explicit/README.md +++ b/seed/csharp-sdk/inferred-auth-explicit/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -111,7 +114,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -124,7 +127,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -154,7 +157,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenWithClientCredentialsAsync(...); +var parsedData = await client.Auth.GetTokenWithClientCredentialsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit.Test/Utils/OptionalComparer.cs index dc26200f7f74..41bf2dc23210 100644 --- a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/Extensions.cs b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/Extensions.cs index cd9f308074eb..1f996c0b73d6 100644 --- a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/Extensions.cs +++ b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/NullableAttribute.cs b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/NullableAttribute.cs index 9fd6b7a69da5..660a4b4ce947 100644 --- a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedInferredAuthExplicit.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedInferredAuthExplicit.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/Optional.cs b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/Optional.cs index 6db41298231f..352703aad376 100644 --- a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/Optional.cs +++ b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/OptionalAttribute.cs b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/OptionalAttribute.cs index 46ffc31febf1..02e1e54a52d6 100644 --- a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedInferredAuthExplicit.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/QueryStringBuilder.cs b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/QueryStringBuilder.cs index 7f507a431b1e..c6da10a8190d 100644 --- a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/SeedInferredAuthExplicit.csproj b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/SeedInferredAuthExplicit.csproj index bf4ca84affd4..3d3c7809acb5 100644 --- a/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/SeedInferredAuthExplicit.csproj +++ b/seed/csharp-sdk/inferred-auth-explicit/src/SeedInferredAuthExplicit/SeedInferredAuthExplicit.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/inferred-auth-explicit/fern + https://github.com/inferred-auth-explicit/fern + git true diff --git a/seed/csharp-sdk/inferred-auth-implicit-api-key/README.md b/seed/csharp-sdk/inferred-auth-implicit-api-key/README.md index 599f51c12512..bf876b5e51fb 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-api-key/README.md +++ b/seed/csharp-sdk/inferred-auth-implicit-api-key/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenAsync(...); +var parsedData = await client.Auth.GetTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey.Test/Utils/OptionalComparer.cs index a35fdf54d00c..ede7a9db3b9d 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/Extensions.cs b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/Extensions.cs index ec8d27fd16a7..b3d7bf835a81 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/Extensions.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/NullableAttribute.cs b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/NullableAttribute.cs index 59ad28b72918..7f0300513bc5 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedInferredAuthImplicitApiKey.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedInferredAuthImplicitApiKey.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/Optional.cs b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/Optional.cs index 0c4c01bfd1db..695b4da60705 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/Optional.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/OptionalAttribute.cs b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/OptionalAttribute.cs index 7aaa7a1d126d..2eecd499d8a0 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedInferredAuthImplicitApiKey.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/QueryStringBuilder.cs b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/QueryStringBuilder.cs index d894481d1c0b..f4dbd994f6f9 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/SeedInferredAuthImplicitApiKey.csproj b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/SeedInferredAuthImplicitApiKey.csproj index 5dde7d0ddaad..4adda1dc3b56 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/SeedInferredAuthImplicitApiKey.csproj +++ b/seed/csharp-sdk/inferred-auth-implicit-api-key/src/SeedInferredAuthImplicitApiKey/SeedInferredAuthImplicitApiKey.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/inferred-auth-implicit-api-key/fern + https://github.com/inferred-auth-implicit-api-key/fern + git true diff --git a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/README.md b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/README.md index e168172ab0dd..34aebb77fdef 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/README.md +++ b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -111,7 +114,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -124,7 +127,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -154,7 +157,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenWithClientCredentialsAsync(...); +var parsedData = await client.Auth.GetTokenWithClientCredentialsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry.Test/Utils/OptionalComparer.cs index 29d462e8b6f1..16f2a37d5d60 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/Extensions.cs b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/Extensions.cs index cc2c07e871d8..c37c081dad58 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/Extensions.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/NullableAttribute.cs b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/NullableAttribute.cs index d1ff98ab2e1a..6e42cb44f345 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedInferredAuthImplicitNoExpiry.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedInferredAuthImplicitNoExpiry.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/Optional.cs b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/Optional.cs index 0ff3f5073388..5094945e10cd 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/Optional.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/OptionalAttribute.cs b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/OptionalAttribute.cs index 726ea6491e2b..aa1cc1b8d89f 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedInferredAuthImplicitNoExpiry.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/QueryStringBuilder.cs b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/QueryStringBuilder.cs index 3a0717a5e0a7..92fbbc9a369e 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/SeedInferredAuthImplicitNoExpiry.csproj b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/SeedInferredAuthImplicitNoExpiry.csproj index c1b2d8c49979..cbe68d988f6f 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/SeedInferredAuthImplicitNoExpiry.csproj +++ b/seed/csharp-sdk/inferred-auth-implicit-no-expiry/src/SeedInferredAuthImplicitNoExpiry/SeedInferredAuthImplicitNoExpiry.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/inferred-auth-implicit-no-expiry/fern + https://github.com/inferred-auth-implicit-no-expiry/fern + git true diff --git a/seed/csharp-sdk/inferred-auth-implicit-reference/README.md b/seed/csharp-sdk/inferred-auth-implicit-reference/README.md index c0bfac261fd7..53ef619acd89 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-reference/README.md +++ b/seed/csharp-sdk/inferred-auth-implicit-reference/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -110,7 +113,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -123,7 +126,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -153,7 +156,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenWithClientCredentialsAsync(...); +var parsedData = await client.Auth.GetTokenWithClientCredentialsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit.Test/Utils/OptionalComparer.cs index 5b8a2a9d6311..60f92c9628a6 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/Extensions.cs b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/Extensions.cs index 7f2286b25a8a..93d16c49deee 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/Extensions.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/NullableAttribute.cs b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/NullableAttribute.cs index bb10fc50c94f..75b86cee4066 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedInferredAuthImplicit.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedInferredAuthImplicit.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/Optional.cs b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/Optional.cs index d5c5da1be252..45ecf2975fa0 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/Optional.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/OptionalAttribute.cs b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/OptionalAttribute.cs index 7bcddf1a849a..e5c254249efd 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedInferredAuthImplicit.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/QueryStringBuilder.cs b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/QueryStringBuilder.cs index d1a611edb4a9..cbdf91788cbb 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/SeedInferredAuthImplicit.csproj b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/SeedInferredAuthImplicit.csproj index 2ae06db1b692..ef05bf66097b 100644 --- a/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/SeedInferredAuthImplicit.csproj +++ b/seed/csharp-sdk/inferred-auth-implicit-reference/src/SeedInferredAuthImplicit/SeedInferredAuthImplicit.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/inferred-auth-implicit-reference/fern + https://github.com/inferred-auth-implicit-reference/fern + git true diff --git a/seed/csharp-sdk/inferred-auth-implicit/README.md b/seed/csharp-sdk/inferred-auth-implicit/README.md index d12ba290553c..1e7e0b5fc2d0 100644 --- a/seed/csharp-sdk/inferred-auth-implicit/README.md +++ b/seed/csharp-sdk/inferred-auth-implicit/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -111,7 +114,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -124,7 +127,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -154,7 +157,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenWithClientCredentialsAsync(...); +var parsedData = await client.Auth.GetTokenWithClientCredentialsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit.Test/Utils/OptionalComparer.cs index 5b8a2a9d6311..60f92c9628a6 100644 --- a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/Extensions.cs b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/Extensions.cs index 7f2286b25a8a..93d16c49deee 100644 --- a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/Extensions.cs +++ b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/NullableAttribute.cs b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/NullableAttribute.cs index bb10fc50c94f..75b86cee4066 100644 --- a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedInferredAuthImplicit.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedInferredAuthImplicit.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/Optional.cs b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/Optional.cs index d5c5da1be252..45ecf2975fa0 100644 --- a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/Optional.cs +++ b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/OptionalAttribute.cs b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/OptionalAttribute.cs index 7bcddf1a849a..e5c254249efd 100644 --- a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedInferredAuthImplicit.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/QueryStringBuilder.cs b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/QueryStringBuilder.cs index d1a611edb4a9..cbdf91788cbb 100644 --- a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/SeedInferredAuthImplicit.csproj b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/SeedInferredAuthImplicit.csproj index 7fe465c62f71..f5b008d5c257 100644 --- a/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/SeedInferredAuthImplicit.csproj +++ b/seed/csharp-sdk/inferred-auth-implicit/src/SeedInferredAuthImplicit/SeedInferredAuthImplicit.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/inferred-auth-implicit/fern + https://github.com/inferred-auth-implicit/fern + git true diff --git a/seed/csharp-sdk/inline-enum-type-name-override/README.md b/seed/csharp-sdk/inline-enum-type-name-override/README.md index f06b80763f66..08952d152965 100644 --- a/seed/csharp-sdk/inline-enum-type-name-override/README.md +++ b/seed/csharp-sdk/inline-enum-type-name-override/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -102,7 +105,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Reporting.LoadAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -115,7 +118,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Reporting.LoadAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -145,7 +148,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Reporting.LoadAsync(...); +var parsedData = await client.Reporting.LoadAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/SeedApi.csproj index 6f0603f83637..ebfe64d358cb 100644 --- a/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/inline-enum-type-name-override/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/inline-enum-type-name-override/fern + https://github.com/inline-enum-type-name-override/fern + git true diff --git a/seed/csharp-sdk/license/custom-license/README.md b/seed/csharp-sdk/license/custom-license/README.md index f060eae03041..16af615fdaff 100644 --- a/seed/csharp-sdk/license/custom-license/README.md +++ b/seed/csharp-sdk/license/custom-license/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetAsync(...); +var parsedData = await client.GetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/license/custom-license/src/SeedLicense.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/license/custom-license/src/SeedLicense.Test/Utils/OptionalComparer.cs index e78679e0feea..aab8889675ce 100644 --- a/seed/csharp-sdk/license/custom-license/src/SeedLicense.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/license/custom-license/src/SeedLicense.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/Extensions.cs b/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/Extensions.cs index 50c06a47850e..f66244d3c511 100644 --- a/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/Extensions.cs +++ b/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/NullableAttribute.cs b/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/NullableAttribute.cs index c1d2efa8cea6..d16292b0ec41 100644 --- a/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedLicense.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedLicense.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/Optional.cs b/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/Optional.cs index 60059e76c0ad..f362be639da4 100644 --- a/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/Optional.cs +++ b/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/OptionalAttribute.cs b/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/OptionalAttribute.cs index e1338150d8f9..c516310d9856 100644 --- a/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedLicense.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/QueryStringBuilder.cs b/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/QueryStringBuilder.cs index 57f979419005..b8119206e1d7 100644 --- a/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/license/custom-license/src/SeedLicense/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/license/custom-license/src/SeedLicense/SeedLicense.csproj b/seed/csharp-sdk/license/custom-license/src/SeedLicense/SeedLicense.csproj index 4d0d5e5b583b..73f932ab1ee8 100644 --- a/seed/csharp-sdk/license/custom-license/src/SeedLicense/SeedLicense.csproj +++ b/seed/csharp-sdk/license/custom-license/src/SeedLicense/SeedLicense.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/license/fern + https://github.com/license/fern + git true diff --git a/seed/csharp-sdk/license/mit-license/README.md b/seed/csharp-sdk/license/mit-license/README.md index f060eae03041..16af615fdaff 100644 --- a/seed/csharp-sdk/license/mit-license/README.md +++ b/seed/csharp-sdk/license/mit-license/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetAsync(...); +var parsedData = await client.GetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/license/mit-license/src/SeedLicense.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/license/mit-license/src/SeedLicense.Test/Utils/OptionalComparer.cs index e78679e0feea..aab8889675ce 100644 --- a/seed/csharp-sdk/license/mit-license/src/SeedLicense.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/license/mit-license/src/SeedLicense.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/Extensions.cs b/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/Extensions.cs index 50c06a47850e..f66244d3c511 100644 --- a/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/Extensions.cs +++ b/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/NullableAttribute.cs b/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/NullableAttribute.cs index c1d2efa8cea6..d16292b0ec41 100644 --- a/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedLicense.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedLicense.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/Optional.cs b/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/Optional.cs index 60059e76c0ad..f362be639da4 100644 --- a/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/Optional.cs +++ b/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/OptionalAttribute.cs b/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/OptionalAttribute.cs index e1338150d8f9..c516310d9856 100644 --- a/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedLicense.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/QueryStringBuilder.cs b/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/QueryStringBuilder.cs index 57f979419005..b8119206e1d7 100644 --- a/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/license/mit-license/src/SeedLicense/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/license/mit-license/src/SeedLicense/SeedLicense.csproj b/seed/csharp-sdk/license/mit-license/src/SeedLicense/SeedLicense.csproj index 4d0d5e5b583b..73f932ab1ee8 100644 --- a/seed/csharp-sdk/license/mit-license/src/SeedLicense/SeedLicense.csproj +++ b/seed/csharp-sdk/license/mit-license/src/SeedLicense/SeedLicense.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/license/fern + https://github.com/license/fern + git true diff --git a/seed/csharp-sdk/literal-user-agent/README.md b/seed/csharp-sdk/literal-user-agent/README.md index da4b1e8c0d4b..e5843d892a29 100644 --- a/seed/csharp-sdk/literal-user-agent/README.md +++ b/seed/csharp-sdk/literal-user-agent/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.PingAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.PingAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.PingAsync(...); +var parsedData = await client.PingAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent.Test/Utils/OptionalComparer.cs index dec0ea5addfe..a42a03eda02f 100644 --- a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/Extensions.cs b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/Extensions.cs index f55b6cf0b443..2ba63433710b 100644 --- a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/Extensions.cs +++ b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/NullableAttribute.cs b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/NullableAttribute.cs index 4eebb029ea14..1bfe72204ad3 100644 --- a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedLiteralUserAgent.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedLiteralUserAgent.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/Optional.cs b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/Optional.cs index d77bb725e4d1..23bf76f0a9f7 100644 --- a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/Optional.cs +++ b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/OptionalAttribute.cs b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/OptionalAttribute.cs index 20ec81cc11c2..6cfb9c32bcf3 100644 --- a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedLiteralUserAgent.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/Public/ClientOptions.cs b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/Public/ClientOptions.cs index 070f5043098f..b5b429f5c58d 100644 --- a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/Public/ClientOptions.cs +++ b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/Public/ClientOptions.cs @@ -87,6 +87,7 @@ internal ClientOptions Clone() Timeout = Timeout, Headers = new Headers(new Dictionary(Headers)), AdditionalHeaders = AdditionalHeaders, + UserAgent = UserAgent, }; } } diff --git a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/QueryStringBuilder.cs b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/QueryStringBuilder.cs index 57eac7343752..f8dc971dd51d 100644 --- a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/SeedLiteralUserAgent.csproj b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/SeedLiteralUserAgent.csproj index f77be06209fc..28cacbfe744e 100644 --- a/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/SeedLiteralUserAgent.csproj +++ b/seed/csharp-sdk/literal-user-agent/src/SeedLiteralUserAgent/SeedLiteralUserAgent.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/literal-user-agent/fern + https://github.com/literal-user-agent/fern + git true diff --git a/seed/csharp-sdk/literal/no-custom-config/README.md b/seed/csharp-sdk/literal/no-custom-config/README.md index 81d1f6354f9e..975c0c177556 100644 --- a/seed/csharp-sdk/literal/no-custom-config/README.md +++ b/seed/csharp-sdk/literal/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -108,7 +111,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Headers.SendAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -121,7 +124,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Headers.SendAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -151,7 +154,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Headers.SendAsync(...); +var parsedData = await client.Headers.SendAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral.Test/Utils/OptionalComparer.cs index 6c8b44a20bda..02f667c57a4d 100644 --- a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/Extensions.cs b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/Extensions.cs index 367a9df42b95..6f5fa1d66284 100644 --- a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/Extensions.cs +++ b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/NullableAttribute.cs b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/NullableAttribute.cs index 72deefa898bb..afd1ac3849c0 100644 --- a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedLiteral.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedLiteral.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/Optional.cs b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/Optional.cs index d6e5b0f7d248..e853c0eef847 100644 --- a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/Optional.cs +++ b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/OptionalAttribute.cs b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/OptionalAttribute.cs index 8c2daa65fd53..caeb77b19bf2 100644 --- a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedLiteral.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/Public/ClientOptions.cs b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/Public/ClientOptions.cs index 90c318872afe..e0ae548f17da 100644 --- a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/Public/ClientOptions.cs +++ b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/Public/ClientOptions.cs @@ -95,6 +95,8 @@ internal ClientOptions Clone() Timeout = Timeout, Headers = new Headers(new Dictionary(Headers)), AdditionalHeaders = AdditionalHeaders, + Version = Version, + AuditLogging = AuditLogging, }; } } diff --git a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/QueryStringBuilder.cs b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/QueryStringBuilder.cs index cca8ed9ab75b..380862dda279 100644 --- a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/SeedLiteral.csproj b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/SeedLiteral.csproj index fe7a1de13413..53d6881b0475 100644 --- a/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/SeedLiteral.csproj +++ b/seed/csharp-sdk/literal/no-custom-config/src/SeedLiteral/SeedLiteral.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/literal/fern + https://github.com/literal/fern + git true diff --git a/seed/csharp-sdk/literal/readonly-constants/README.md b/seed/csharp-sdk/literal/readonly-constants/README.md index 81d1f6354f9e..975c0c177556 100644 --- a/seed/csharp-sdk/literal/readonly-constants/README.md +++ b/seed/csharp-sdk/literal/readonly-constants/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -108,7 +111,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Headers.SendAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -121,7 +124,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Headers.SendAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -151,7 +154,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Headers.SendAsync(...); +var parsedData = await client.Headers.SendAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral.Test/Utils/OptionalComparer.cs index 6c8b44a20bda..02f667c57a4d 100644 --- a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/Extensions.cs b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/Extensions.cs index 367a9df42b95..6f5fa1d66284 100644 --- a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/Extensions.cs +++ b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/NullableAttribute.cs b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/NullableAttribute.cs index 72deefa898bb..afd1ac3849c0 100644 --- a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedLiteral.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedLiteral.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/Optional.cs b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/Optional.cs index d6e5b0f7d248..e853c0eef847 100644 --- a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/Optional.cs +++ b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/OptionalAttribute.cs b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/OptionalAttribute.cs index 8c2daa65fd53..caeb77b19bf2 100644 --- a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedLiteral.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/Public/ClientOptions.cs b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/Public/ClientOptions.cs index 90c318872afe..e0ae548f17da 100644 --- a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/Public/ClientOptions.cs +++ b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/Public/ClientOptions.cs @@ -95,6 +95,8 @@ internal ClientOptions Clone() Timeout = Timeout, Headers = new Headers(new Dictionary(Headers)), AdditionalHeaders = AdditionalHeaders, + Version = Version, + AuditLogging = AuditLogging, }; } } diff --git a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/QueryStringBuilder.cs b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/QueryStringBuilder.cs index cca8ed9ab75b..380862dda279 100644 --- a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/SeedLiteral.csproj b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/SeedLiteral.csproj index fe7a1de13413..53d6881b0475 100644 --- a/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/SeedLiteral.csproj +++ b/seed/csharp-sdk/literal/readonly-constants/src/SeedLiteral/SeedLiteral.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/literal/fern + https://github.com/literal/fern + git true diff --git a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions.Test/Utils/OptionalComparer.cs index ed355509f3a7..f81be6b471fa 100644 --- a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/Extensions.cs b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/Extensions.cs index a0007d3e924f..61c5660560b6 100644 --- a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/Extensions.cs +++ b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/NullableAttribute.cs b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/NullableAttribute.cs index f90583c67e6c..a94921684393 100644 --- a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedLiteralsUnions.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedLiteralsUnions.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/Optional.cs b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/Optional.cs index d30d500746f6..405ef075d44e 100644 --- a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/Optional.cs +++ b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/OptionalAttribute.cs b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/OptionalAttribute.cs index 7955b603066b..a421018a7c2f 100644 --- a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedLiteralsUnions.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/QueryStringBuilder.cs b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/QueryStringBuilder.cs index 425aaedf411e..3baebcc19ece 100644 --- a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/SeedLiteralsUnions.csproj b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/SeedLiteralsUnions.csproj index 83e9ed30b933..37b3ca22d0e1 100644 --- a/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/SeedLiteralsUnions.csproj +++ b/seed/csharp-sdk/literals-unions/src/SeedLiteralsUnions/SeedLiteralsUnions.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/literals-unions/fern + https://github.com/literals-unions/fern + git true diff --git a/seed/csharp-sdk/mixed-case/README.md b/seed/csharp-sdk/mixed-case/README.md index 3f7374dd3d30..0ee1652535cf 100644 --- a/seed/csharp-sdk/mixed-case/README.md +++ b/seed/csharp-sdk/mixed-case/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -102,7 +105,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.GetResourceAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -115,7 +118,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.GetResourceAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -145,7 +148,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.GetResourceAsync(...); +var parsedData = await client.Service.GetResourceAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/mixed-case/src/SeedMixedCase.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/mixed-case/src/SeedMixedCase.Test/Utils/OptionalComparer.cs index 9fbfc97fa8e2..afa0dfc68518 100644 --- a/seed/csharp-sdk/mixed-case/src/SeedMixedCase.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/mixed-case/src/SeedMixedCase.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/Extensions.cs b/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/Extensions.cs index 4fa8437010b2..e397717586d8 100644 --- a/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/Extensions.cs +++ b/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/NullableAttribute.cs b/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/NullableAttribute.cs index 5167799e96aa..bfae20072a76 100644 --- a/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedMixedCase.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedMixedCase.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/Optional.cs b/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/Optional.cs index 9522066fb2c3..7421b880c04b 100644 --- a/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/Optional.cs +++ b/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/OptionalAttribute.cs b/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/OptionalAttribute.cs index 3fb6cf1d6994..2a97d1b0b9b1 100644 --- a/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedMixedCase.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/QueryStringBuilder.cs b/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/QueryStringBuilder.cs index 03af1496ef0b..f0c280d0b53a 100644 --- a/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/mixed-case/src/SeedMixedCase/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/mixed-case/src/SeedMixedCase/SeedMixedCase.csproj b/seed/csharp-sdk/mixed-case/src/SeedMixedCase/SeedMixedCase.csproj index 345ed14dbfec..0ef490d89276 100644 --- a/seed/csharp-sdk/mixed-case/src/SeedMixedCase/SeedMixedCase.csproj +++ b/seed/csharp-sdk/mixed-case/src/SeedMixedCase/SeedMixedCase.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/mixed-case/fern + https://github.com/mixed-case/fern + git true diff --git a/seed/csharp-sdk/mixed-file-directory/README.md b/seed/csharp-sdk/mixed-file-directory/README.md index 146374840375..7df7d2770ea6 100644 --- a/seed/csharp-sdk/mixed-file-directory/README.md +++ b/seed/csharp-sdk/mixed-file-directory/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Organization.CreateAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Organization.CreateAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Organization.CreateAsync(...); +var parsedData = await client.Organization.CreateAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory.Test/Utils/OptionalComparer.cs index 74e3b65e6153..c6fa0342e510 100644 --- a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/Extensions.cs b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/Extensions.cs index 023952155c90..4487888491a7 100644 --- a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/Extensions.cs +++ b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/NullableAttribute.cs b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/NullableAttribute.cs index 93520576e325..bf738bfe133f 100644 --- a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedMixedFileDirectory.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedMixedFileDirectory.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/Optional.cs b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/Optional.cs index a92124d756b9..fe1f229e3529 100644 --- a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/Optional.cs +++ b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/OptionalAttribute.cs b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/OptionalAttribute.cs index 8d653ed8c408..de74e140fbd9 100644 --- a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedMixedFileDirectory.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/QueryStringBuilder.cs b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/QueryStringBuilder.cs index 076c11e8f52b..7488517d31c1 100644 --- a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/SeedMixedFileDirectory.csproj b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/SeedMixedFileDirectory.csproj index 3a193047814a..599fa9200a4c 100644 --- a/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/SeedMixedFileDirectory.csproj +++ b/seed/csharp-sdk/mixed-file-directory/src/SeedMixedFileDirectory/SeedMixedFileDirectory.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/mixed-file-directory/fern + https://github.com/mixed-file-directory/fern + git true diff --git a/seed/csharp-sdk/multi-content-type-examples/README.md b/seed/csharp-sdk/multi-content-type-examples/README.md index 6587dbb8fd30..09dc161fdb99 100644 --- a/seed/csharp-sdk/multi-content-type-examples/README.md +++ b/seed/csharp-sdk/multi-content-type-examples/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -106,7 +109,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Clients.CreateAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -119,7 +122,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Clients.CreateAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -149,7 +152,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Clients.CreateAsync(...); +var parsedData = await client.Clients.CreateAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/SeedApi.csproj index 87d76f98dd0c..4b3fc5e304aa 100644 --- a/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/multi-content-type-examples/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/multi-content-type-examples/fern + https://github.com/multi-content-type-examples/fern + git true diff --git a/seed/csharp-sdk/multi-line-docs/README.md b/seed/csharp-sdk/multi-line-docs/README.md index 653504adc629..fd858b5584ef 100644 --- a/seed/csharp-sdk/multi-line-docs/README.md +++ b/seed/csharp-sdk/multi-line-docs/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -102,7 +105,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -115,7 +118,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -145,7 +148,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.CreateUserAsync(...); +var parsedData = await client.User.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs.Test/Utils/OptionalComparer.cs index 5cd96f97a36f..bbf75497f44a 100644 --- a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/Extensions.cs b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/Extensions.cs index 26d9e506f126..e072189d7a45 100644 --- a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/Extensions.cs +++ b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/NullableAttribute.cs b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/NullableAttribute.cs index 2aef34eac360..fd809194698c 100644 --- a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedMultiLineDocs.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedMultiLineDocs.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/Optional.cs b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/Optional.cs index 0e32df47fb46..3bd0a5648792 100644 --- a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/Optional.cs +++ b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/OptionalAttribute.cs b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/OptionalAttribute.cs index bb0a06db7092..c91413e29bb0 100644 --- a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedMultiLineDocs.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/QueryStringBuilder.cs b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/QueryStringBuilder.cs index 35366f6f53f1..92113092dd12 100644 --- a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/SeedMultiLineDocs.csproj b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/SeedMultiLineDocs.csproj index 6136257433fb..e629ab162b06 100644 --- a/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/SeedMultiLineDocs.csproj +++ b/seed/csharp-sdk/multi-line-docs/src/SeedMultiLineDocs/SeedMultiLineDocs.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/multi-line-docs/fern + https://github.com/multi-line-docs/fern + git true diff --git a/seed/csharp-sdk/multi-url-environment-no-default/README.md b/seed/csharp-sdk/multi-url-environment-no-default/README.md index 04f76a65df69..0ce479ce5202 100644 --- a/seed/csharp-sdk/multi-url-environment-no-default/README.md +++ b/seed/csharp-sdk/multi-url-environment-no-default/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Ec2.BootInstanceAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Ec2.BootInstanceAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Ec2.BootInstanceAsync(...); +var parsedData = await client.Ec2.BootInstanceAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault.Test/Utils/OptionalComparer.cs index c982659a843d..9b769bac8470 100644 --- a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/Extensions.cs b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/Extensions.cs index 880da7f1d3cf..cb8615590724 100644 --- a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/Extensions.cs +++ b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/NullableAttribute.cs b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/NullableAttribute.cs index 9ff7f264c09b..a30684878b5d 100644 --- a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedMultiUrlEnvironmentNoDefault.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedMultiUrlEnvironmentNoDefault.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/Optional.cs b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/Optional.cs index f537b791bee3..ddfb4fe8e3fe 100644 --- a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/Optional.cs +++ b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/OptionalAttribute.cs b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/OptionalAttribute.cs index 3ff651e0129f..4bf698ba079c 100644 --- a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedMultiUrlEnvironmentNoDefault.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/QueryStringBuilder.cs b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/QueryStringBuilder.cs index cacc6c204608..64cdcf90fbe8 100644 --- a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/SeedMultiUrlEnvironmentNoDefault.csproj b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/SeedMultiUrlEnvironmentNoDefault.csproj index 3c0bc28d7b16..fee034286619 100644 --- a/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/SeedMultiUrlEnvironmentNoDefault.csproj +++ b/seed/csharp-sdk/multi-url-environment-no-default/src/SeedMultiUrlEnvironmentNoDefault/SeedMultiUrlEnvironmentNoDefault.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/multi-url-environment-no-default/fern + https://github.com/multi-url-environment-no-default/fern + git true diff --git a/seed/csharp-sdk/multi-url-environment-reference/README.md b/seed/csharp-sdk/multi-url-environment-reference/README.md index a5c3e11b004c..f4f60997bc1f 100644 --- a/seed/csharp-sdk/multi-url-environment-reference/README.md +++ b/seed/csharp-sdk/multi-url-environment-reference/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -117,7 +120,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GettokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -130,7 +133,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GettokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -160,7 +163,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GettokenAsync(...); +var parsedData = await client.Auth.GettokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/SeedApi.csproj index f7519a006920..1f6068b5bf01 100644 --- a/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/multi-url-environment-reference/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/multi-url-environment-reference/fern + https://github.com/multi-url-environment-reference/fern + git true diff --git a/seed/csharp-sdk/multi-url-environment/environment-class-name/README.md b/seed/csharp-sdk/multi-url-environment/environment-class-name/README.md index 76e6d6ff1ee3..dab1aae3e611 100644 --- a/seed/csharp-sdk/multi-url-environment/environment-class-name/README.md +++ b/seed/csharp-sdk/multi-url-environment/environment-class-name/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Ec2.BootInstanceAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Ec2.BootInstanceAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Ec2.BootInstanceAsync(...); +var parsedData = await client.Ec2.BootInstanceAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment.Test/Utils/OptionalComparer.cs index b0b56617d895..93a459e74391 100644 --- a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/Extensions.cs b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/Extensions.cs index 5f62ee76455c..50af7681b369 100644 --- a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/Extensions.cs +++ b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/NullableAttribute.cs b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/NullableAttribute.cs index 84b03d0be753..8ee5726b08ec 100644 --- a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedMultiUrlEnvironment.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedMultiUrlEnvironment.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/Optional.cs b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/Optional.cs index 879ad30fad67..25bb3d2db547 100644 --- a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/Optional.cs +++ b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/OptionalAttribute.cs b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/OptionalAttribute.cs index 63b2842505e2..da32e845469b 100644 --- a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedMultiUrlEnvironment.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/QueryStringBuilder.cs b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/QueryStringBuilder.cs index f2db95b27bee..2f6b3e7a823f 100644 --- a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/SeedMultiUrlEnvironment.csproj b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/SeedMultiUrlEnvironment.csproj index 6e7693d67a53..3b1d75735723 100644 --- a/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/SeedMultiUrlEnvironment.csproj +++ b/seed/csharp-sdk/multi-url-environment/environment-class-name/src/SeedMultiUrlEnvironment/SeedMultiUrlEnvironment.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/multi-url-environment/fern + https://github.com/multi-url-environment/fern + git true diff --git a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/README.md b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/README.md index 043af58ab8a3..4deacd4e2f37 100644 --- a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/README.md +++ b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Ec2.BootInstanceAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Ec2.BootInstanceAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Ec2.BootInstanceAsync(...); +var parsedData = await client.Ec2.BootInstanceAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment.Test/Utils/OptionalComparer.cs index b0b56617d895..93a459e74391 100644 --- a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/Extensions.cs b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/Extensions.cs index 5f62ee76455c..50af7681b369 100644 --- a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/Extensions.cs +++ b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/NullableAttribute.cs b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/NullableAttribute.cs index 84b03d0be753..8ee5726b08ec 100644 --- a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedMultiUrlEnvironment.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedMultiUrlEnvironment.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/Optional.cs b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/Optional.cs index 879ad30fad67..25bb3d2db547 100644 --- a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/Optional.cs +++ b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/OptionalAttribute.cs b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/OptionalAttribute.cs index 63b2842505e2..da32e845469b 100644 --- a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedMultiUrlEnvironment.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/QueryStringBuilder.cs b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/QueryStringBuilder.cs index f2db95b27bee..2f6b3e7a823f 100644 --- a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/SeedMultiUrlEnvironment.csproj b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/SeedMultiUrlEnvironment.csproj index 6e7693d67a53..3b1d75735723 100644 --- a/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/SeedMultiUrlEnvironment.csproj +++ b/seed/csharp-sdk/multi-url-environment/no-pascal-case-environments/src/SeedMultiUrlEnvironment/SeedMultiUrlEnvironment.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/multi-url-environment/fern + https://github.com/multi-url-environment/fern + git true diff --git a/seed/csharp-sdk/multiple-request-bodies/README.md b/seed/csharp-sdk/multiple-request-bodies/README.md index 72e35f93fba0..59d7f6242ed8 100644 --- a/seed/csharp-sdk/multiple-request-bodies/README.md +++ b/seed/csharp-sdk/multiple-request-bodies/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.UploadJsonDocumentAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.UploadJsonDocumentAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.UploadJsonDocumentAsync(...); +var parsedData = await client.UploadJsonDocumentAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/SeedApi.csproj index 994cbe182d1d..4bd64c06508a 100644 --- a/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/multiple-request-bodies/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/multiple-request-bodies/fern + https://github.com/multiple-request-bodies/fern + git true diff --git a/seed/csharp-sdk/no-content-response/README.md b/seed/csharp-sdk/no-content-response/README.md index fe55ee20f4f3..c1c8253b707b 100644 --- a/seed/csharp-sdk/no-content-response/README.md +++ b/seed/csharp-sdk/no-content-response/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Contacts.CreateAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Contacts.CreateAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Contacts.CreateAsync(...); +var parsedData = await client.Contacts.CreateAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/no-content-response/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/no-content-response/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/no-content-response/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/no-content-response/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/no-content-response/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/no-content-response/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/no-content-response/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/no-content-response/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/no-content-response/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/no-content-response/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/no-content-response/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/no-content-response/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/no-content-response/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/no-content-response/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/no-content-response/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/no-content-response/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/no-content-response/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/no-content-response/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/no-content-response/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/no-content-response/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/no-content-response/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/no-content-response/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/no-content-response/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/no-content-response/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/no-content-response/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/no-content-response/src/SeedApi/SeedApi.csproj index bb144e39c2c7..506fc58f1384 100644 --- a/seed/csharp-sdk/no-content-response/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/no-content-response/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/no-content-response/fern + https://github.com/no-content-response/fern + git true diff --git a/seed/csharp-sdk/no-environment/README.md b/seed/csharp-sdk/no-environment/README.md index de8ad1675b17..599fe47c4050 100644 --- a/seed/csharp-sdk/no-environment/README.md +++ b/seed/csharp-sdk/no-environment/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Dummy.GetDummyAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Dummy.GetDummyAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Dummy.GetDummyAsync(...); +var parsedData = await client.Dummy.GetDummyAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment.Test/Utils/OptionalComparer.cs index 9429d79eec13..aad99959b976 100644 --- a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/Extensions.cs b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/Extensions.cs index f7008677db93..e360e9d5b496 100644 --- a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/Extensions.cs +++ b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/NullableAttribute.cs b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/NullableAttribute.cs index a1d73d3ffe0a..59878d36bb27 100644 --- a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedNoEnvironment.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedNoEnvironment.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/Optional.cs b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/Optional.cs index 8b46fda13a3c..48c5622dd390 100644 --- a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/Optional.cs +++ b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/OptionalAttribute.cs b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/OptionalAttribute.cs index e723913a218d..4e7f5abbd78e 100644 --- a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedNoEnvironment.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/QueryStringBuilder.cs b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/QueryStringBuilder.cs index 15f911e93825..a919b9f6ed79 100644 --- a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/SeedNoEnvironment.csproj b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/SeedNoEnvironment.csproj index be3c210bd6ac..36df36243d06 100644 --- a/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/SeedNoEnvironment.csproj +++ b/seed/csharp-sdk/no-environment/src/SeedNoEnvironment/SeedNoEnvironment.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/no-environment/fern + https://github.com/no-environment/fern + git true diff --git a/seed/csharp-sdk/no-retries/README.md b/seed/csharp-sdk/no-retries/README.md index 44b68ee9cc28..d8e67153135f 100644 --- a/seed/csharp-sdk/no-retries/README.md +++ b/seed/csharp-sdk/no-retries/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Retries.GetUsersAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Retries.GetUsersAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Retries.GetUsersAsync(...); +var parsedData = await client.Retries.GetUsersAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/no-retries/src/SeedNoRetries.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/no-retries/src/SeedNoRetries.Test/Utils/OptionalComparer.cs index 7910f774d98a..87abbc83717f 100644 --- a/seed/csharp-sdk/no-retries/src/SeedNoRetries.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/no-retries/src/SeedNoRetries.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/Extensions.cs b/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/Extensions.cs index c1831f6bf5a7..b737c385eb84 100644 --- a/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/Extensions.cs +++ b/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/NullableAttribute.cs b/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/NullableAttribute.cs index 479e1e3a9ffb..4de89a304769 100644 --- a/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedNoRetries.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedNoRetries.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/Optional.cs b/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/Optional.cs index c6f3212050bd..aaa8a743cba0 100644 --- a/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/Optional.cs +++ b/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/OptionalAttribute.cs b/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/OptionalAttribute.cs index 6a74390c1039..21761950b9cd 100644 --- a/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedNoRetries.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/QueryStringBuilder.cs b/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/QueryStringBuilder.cs index bb4ad7694bf7..78e2945cb57e 100644 --- a/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/no-retries/src/SeedNoRetries/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/no-retries/src/SeedNoRetries/SeedNoRetries.csproj b/seed/csharp-sdk/no-retries/src/SeedNoRetries/SeedNoRetries.csproj index 5060ea0b11e0..b5dfb7ebf5b2 100644 --- a/seed/csharp-sdk/no-retries/src/SeedNoRetries/SeedNoRetries.csproj +++ b/seed/csharp-sdk/no-retries/src/SeedNoRetries/SeedNoRetries.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/no-retries/fern + https://github.com/no-retries/fern + git true diff --git a/seed/csharp-sdk/null-type/README.md b/seed/csharp-sdk/null-type/README.md index 56961a18d0a8..2065c089b2e3 100644 --- a/seed/csharp-sdk/null-type/README.md +++ b/seed/csharp-sdk/null-type/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Conversations.OutboundCallAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Conversations.OutboundCallAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Conversations.OutboundCallAsync(...); +var parsedData = await client.Conversations.OutboundCallAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/null-type/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/null-type/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/null-type/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/null-type/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/null-type/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/null-type/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/null-type/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/null-type/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/null-type/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/null-type/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/null-type/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/null-type/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/null-type/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/null-type/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/null-type/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/null-type/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/null-type/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/null-type/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/null-type/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/null-type/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/null-type/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/null-type/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/null-type/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/null-type/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/null-type/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/null-type/src/SeedApi/SeedApi.csproj index f6f183afc9aa..4541bc02873d 100644 --- a/seed/csharp-sdk/null-type/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/null-type/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/null-type/fern + https://github.com/null-type/fern + git true diff --git a/seed/csharp-sdk/nullable-allof-extends/README.md b/seed/csharp-sdk/nullable-allof-extends/README.md index 3f56bd5e851b..237feb51d35f 100644 --- a/seed/csharp-sdk/nullable-allof-extends/README.md +++ b/seed/csharp-sdk/nullable-allof-extends/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreateTestAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreateTestAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreateTestAsync(...); +var parsedData = await client.CreateTestAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/SeedApi.csproj index 79852ebfba87..10cfcf98db28 100644 --- a/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/nullable-allof-extends/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/nullable-allof-extends/fern + https://github.com/nullable-allof-extends/fern + git true diff --git a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/README.md b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/README.md index a987e568e2d4..9a707d49c45b 100644 --- a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/README.md +++ b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -119,7 +122,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.NullableOptional.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -132,7 +135,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.NullableOptional.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -162,7 +165,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.NullableOptional.CreateUserAsync(...); +var parsedData = await client.NullableOptional.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional.Test/Utils/OptionalComparer.cs index d5475baf78a4..7ee602831c69 100644 --- a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/Extensions.cs b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/Extensions.cs index 7af0d33c31cf..f37f9fafdb3b 100644 --- a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/Extensions.cs +++ b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/NullableAttribute.cs b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/NullableAttribute.cs index 581e75c48a3d..75bfc857d312 100644 --- a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedNullableOptional.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedNullableOptional.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/Optional.cs b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/Optional.cs index 7d11744ea4d8..9d940199acc0 100644 --- a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/Optional.cs +++ b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/OptionalAttribute.cs b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/OptionalAttribute.cs index 471fcdfe836d..b4a0acc1b53b 100644 --- a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedNullableOptional.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/QueryStringBuilder.cs b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/QueryStringBuilder.cs index b61a5f96906d..87b9d7b9d73e 100644 --- a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/SeedNullableOptional.csproj b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/SeedNullableOptional.csproj index 6796da0a4d69..017ae5975f1c 100644 --- a/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/SeedNullableOptional.csproj +++ b/seed/csharp-sdk/nullable-optional/explicit-nullable-optional/src/SeedNullableOptional/SeedNullableOptional.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/nullable-optional/fern + https://github.com/nullable-optional/fern + git true diff --git a/seed/csharp-sdk/nullable-optional/no-custom-config/README.md b/seed/csharp-sdk/nullable-optional/no-custom-config/README.md index a987e568e2d4..9a707d49c45b 100644 --- a/seed/csharp-sdk/nullable-optional/no-custom-config/README.md +++ b/seed/csharp-sdk/nullable-optional/no-custom-config/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -119,7 +122,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.NullableOptional.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -132,7 +135,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.NullableOptional.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -162,7 +165,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.NullableOptional.CreateUserAsync(...); +var parsedData = await client.NullableOptional.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional.Test/Utils/OptionalComparer.cs index d5475baf78a4..7ee602831c69 100644 --- a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/Extensions.cs b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/Extensions.cs index 7af0d33c31cf..f37f9fafdb3b 100644 --- a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/Extensions.cs +++ b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/NullableAttribute.cs b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/NullableAttribute.cs index 581e75c48a3d..75bfc857d312 100644 --- a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedNullableOptional.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedNullableOptional.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/Optional.cs b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/Optional.cs index 7d11744ea4d8..9d940199acc0 100644 --- a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/Optional.cs +++ b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/OptionalAttribute.cs b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/OptionalAttribute.cs index 471fcdfe836d..b4a0acc1b53b 100644 --- a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedNullableOptional.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/QueryStringBuilder.cs b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/QueryStringBuilder.cs index b61a5f96906d..87b9d7b9d73e 100644 --- a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/SeedNullableOptional.csproj b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/SeedNullableOptional.csproj index 6796da0a4d69..017ae5975f1c 100644 --- a/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/SeedNullableOptional.csproj +++ b/seed/csharp-sdk/nullable-optional/no-custom-config/src/SeedNullableOptional/SeedNullableOptional.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/nullable-optional/fern + https://github.com/nullable-optional/fern + git true diff --git a/seed/csharp-sdk/nullable-request-body/README.md b/seed/csharp-sdk/nullable-request-body/README.md index 10dca5644381..4a2498590365 100644 --- a/seed/csharp-sdk/nullable-request-body/README.md +++ b/seed/csharp-sdk/nullable-request-body/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.TestGroup.TestMethodNameAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.TestGroup.TestMethodNameAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.TestGroup.TestMethodNameAsync(...); +var parsedData = await client.TestGroup.TestMethodNameAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/nullable-request-body/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/nullable-request-body/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/nullable-request-body/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/nullable-request-body/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/nullable-request-body/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/nullable-request-body/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/nullable-request-body/src/SeedApi/SeedApi.csproj index 7aba761fe1b2..e6a2fb5acd50 100644 --- a/seed/csharp-sdk/nullable-request-body/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/nullable-request-body/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/nullable-request-body/fern + https://github.com/nullable-request-body/fern + git true diff --git a/seed/csharp-sdk/nullable/explicit-nullable-optional/README.md b/seed/csharp-sdk/nullable/explicit-nullable-optional/README.md index 59e98150427f..9f3880bf6937 100644 --- a/seed/csharp-sdk/nullable/explicit-nullable-optional/README.md +++ b/seed/csharp-sdk/nullable/explicit-nullable-optional/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -117,7 +120,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Nullable.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -130,7 +133,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Nullable.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -160,7 +163,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Nullable.CreateUserAsync(...); +var parsedData = await client.Nullable.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable.Test/Utils/OptionalComparer.cs index ef1b774e662b..3f1e32f7dfd4 100644 --- a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/Extensions.cs b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/Extensions.cs index 8d0989eb1525..c0f360117137 100644 --- a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/Extensions.cs +++ b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/NullableAttribute.cs b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/NullableAttribute.cs index 9456f1ea09bd..79ca5eca0763 100644 --- a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedNullable.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedNullable.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/Optional.cs b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/Optional.cs index 3653953e43ee..4738312ce486 100644 --- a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/Optional.cs +++ b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/OptionalAttribute.cs b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/OptionalAttribute.cs index 51f77f738fef..3b739fd99131 100644 --- a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedNullable.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/QueryStringBuilder.cs b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/QueryStringBuilder.cs index b4bb35daaf0a..9727bc825190 100644 --- a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Nullable/Types/Status.cs b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Nullable/Types/Status.cs index 4e2fda88580e..06a77b7aaeb3 100644 --- a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Nullable/Types/Status.cs +++ b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/Nullable/Types/Status.cs @@ -72,14 +72,14 @@ public Status(Status.SoftDeleted value) public bool IsSoftDeleted => Type == "soft-deleted"; /// - /// Returns the value as a if is 'active', otherwise throws an exception. + /// Returns the value as a if is 'active', otherwise throws an exception. /// /// Thrown when is not 'active'. public object? AsActive() => IsActive ? Value! : throw new global::System.Exception("Status.Type is not 'active'"); /// - /// Returns the value as a if is 'archived', otherwise throws an exception. + /// Returns the value as a if is 'archived', otherwise throws an exception. /// /// Thrown when is not 'archived'. public DateTime? AsArchived() => @@ -88,7 +88,7 @@ public Status(Status.SoftDeleted value) : throw new global::System.Exception("Status.Type is not 'archived'"); /// - /// Returns the value as a if is 'soft-deleted', otherwise throws an exception. + /// Returns the value as a if is 'soft-deleted', otherwise throws an exception. /// /// Thrown when is not 'soft-deleted'. public DateTime? AsSoftDeleted() => @@ -137,7 +137,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsActive(out object? value) { @@ -151,7 +151,7 @@ public bool TryAsActive(out object? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsArchived(out DateTime? value) { @@ -165,7 +165,7 @@ public bool TryAsArchived(out DateTime? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsSoftDeleted(out DateTime? value) { diff --git a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/SeedNullable.csproj b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/SeedNullable.csproj index 8c606873c513..93242e062e59 100644 --- a/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/SeedNullable.csproj +++ b/seed/csharp-sdk/nullable/explicit-nullable-optional/src/SeedNullable/SeedNullable.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/nullable/fern + https://github.com/nullable/fern + git true diff --git a/seed/csharp-sdk/nullable/no-custom-config/README.md b/seed/csharp-sdk/nullable/no-custom-config/README.md index 59e98150427f..9f3880bf6937 100644 --- a/seed/csharp-sdk/nullable/no-custom-config/README.md +++ b/seed/csharp-sdk/nullable/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -117,7 +120,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Nullable.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -130,7 +133,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Nullable.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -160,7 +163,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Nullable.CreateUserAsync(...); +var parsedData = await client.Nullable.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable.Test/Utils/OptionalComparer.cs index ef1b774e662b..3f1e32f7dfd4 100644 --- a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/Extensions.cs b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/Extensions.cs index 8d0989eb1525..c0f360117137 100644 --- a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/Extensions.cs +++ b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/NullableAttribute.cs b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/NullableAttribute.cs index 9456f1ea09bd..79ca5eca0763 100644 --- a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedNullable.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedNullable.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/Optional.cs b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/Optional.cs index 3653953e43ee..4738312ce486 100644 --- a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/Optional.cs +++ b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/OptionalAttribute.cs b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/OptionalAttribute.cs index 51f77f738fef..3b739fd99131 100644 --- a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedNullable.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/QueryStringBuilder.cs b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/QueryStringBuilder.cs index b4bb35daaf0a..9727bc825190 100644 --- a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Nullable/Types/Status.cs b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Nullable/Types/Status.cs index 4e2fda88580e..06a77b7aaeb3 100644 --- a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Nullable/Types/Status.cs +++ b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/Nullable/Types/Status.cs @@ -72,14 +72,14 @@ public Status(Status.SoftDeleted value) public bool IsSoftDeleted => Type == "soft-deleted"; /// - /// Returns the value as a if is 'active', otherwise throws an exception. + /// Returns the value as a if is 'active', otherwise throws an exception. /// /// Thrown when is not 'active'. public object? AsActive() => IsActive ? Value! : throw new global::System.Exception("Status.Type is not 'active'"); /// - /// Returns the value as a if is 'archived', otherwise throws an exception. + /// Returns the value as a if is 'archived', otherwise throws an exception. /// /// Thrown when is not 'archived'. public DateTime? AsArchived() => @@ -88,7 +88,7 @@ public Status(Status.SoftDeleted value) : throw new global::System.Exception("Status.Type is not 'archived'"); /// - /// Returns the value as a if is 'soft-deleted', otherwise throws an exception. + /// Returns the value as a if is 'soft-deleted', otherwise throws an exception. /// /// Thrown when is not 'soft-deleted'. public DateTime? AsSoftDeleted() => @@ -137,7 +137,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsActive(out object? value) { @@ -151,7 +151,7 @@ public bool TryAsActive(out object? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsArchived(out DateTime? value) { @@ -165,7 +165,7 @@ public bool TryAsArchived(out DateTime? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsSoftDeleted(out DateTime? value) { diff --git a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/SeedNullable.csproj b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/SeedNullable.csproj index 8c606873c513..93242e062e59 100644 --- a/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/SeedNullable.csproj +++ b/seed/csharp-sdk/nullable/no-custom-config/src/SeedNullable/SeedNullable.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/nullable/fern + https://github.com/nullable/fern + git true diff --git a/seed/csharp-sdk/oauth-client-credentials-custom/README.md b/seed/csharp-sdk/oauth-client-credentials-custom/README.md index d559ae81e760..43743a1f0e95 100644 --- a/seed/csharp-sdk/oauth-client-credentials-custom/README.md +++ b/seed/csharp-sdk/oauth-client-credentials-custom/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -113,7 +116,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -126,7 +129,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -156,7 +159,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenWithClientCredentialsAsync(...); +var parsedData = await client.Auth.GetTokenWithClientCredentialsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs index 9592099f4ada..7e1d89d6a924 100644 --- a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/Extensions.cs b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/Extensions.cs index 05db0ec05881..3dfb846f50ed 100644 --- a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/Extensions.cs +++ b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/NullableAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/NullableAttribute.cs index 20f4b72c9468..8acacb080e25 100644 --- a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedOauthClientCredentials.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedOauthClientCredentials.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/Optional.cs b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/Optional.cs index 25fc6d0298dd..74130f54fcb0 100644 --- a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/Optional.cs +++ b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs index 825eb2f3d589..83dbc98f0b3e 100644 --- a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedOauthClientCredentials.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs index 12ec33f1a6df..a2f0a7457051 100644 --- a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj index 043852463408..5192986c6ae0 100644 --- a/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj +++ b/seed/csharp-sdk/oauth-client-credentials-custom/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/oauth-client-credentials-custom/fern + https://github.com/oauth-client-credentials-custom/fern + git true diff --git a/seed/csharp-sdk/oauth-client-credentials-default/README.md b/seed/csharp-sdk/oauth-client-credentials-default/README.md index 1ae5d6becb48..4c7cd5bf1533 100644 --- a/seed/csharp-sdk/oauth-client-credentials-default/README.md +++ b/seed/csharp-sdk/oauth-client-credentials-default/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -108,7 +111,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -121,7 +124,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -151,7 +154,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenAsync(...); +var parsedData = await client.Auth.GetTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/Utils/OptionalComparer.cs index d69e4e170244..5c37c5b0fda0 100644 --- a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/Extensions.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/Extensions.cs index 6a2ffd98f629..22ec93a7b3bd 100644 --- a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/Extensions.cs +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/NullableAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/NullableAttribute.cs index 57894ed84002..d857fab6b4f4 100644 --- a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedOauthClientCredentialsDefault.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedOauthClientCredentialsDefault.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/Optional.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/Optional.cs index a24856f80199..cb45887473d2 100644 --- a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/Optional.cs +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/OptionalAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/OptionalAttribute.cs index a9e75767ec9e..47af9d0ce869 100644 --- a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedOauthClientCredentialsDefault.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/QueryStringBuilder.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/QueryStringBuilder.cs index 10726d2ed383..98a8b8fd325f 100644 --- a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj index eeb84689b24f..4f88aae777b3 100644 --- a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/oauth-client-credentials-default/fern + https://github.com/oauth-client-credentials-default/fern + git true diff --git a/seed/csharp-sdk/oauth-client-credentials-environment-variables/README.md b/seed/csharp-sdk/oauth-client-credentials-environment-variables/README.md index 7e38e9e48541..205c7805f468 100644 --- a/seed/csharp-sdk/oauth-client-credentials-environment-variables/README.md +++ b/seed/csharp-sdk/oauth-client-credentials-environment-variables/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -110,7 +113,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -123,7 +126,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -153,7 +156,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenWithClientCredentialsAsync(...); +var parsedData = await client.Auth.GetTokenWithClientCredentialsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables.Test/Utils/OptionalComparer.cs index a63d81e13d4a..3575ce42ff0a 100644 --- a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/Extensions.cs b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/Extensions.cs index 3e25c13d7466..314882d2d5e2 100644 --- a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/Extensions.cs +++ b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/NullableAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/NullableAttribute.cs index 3b04e43931be..c7a09dbc8ec4 100644 --- a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedOauthClientCredentialsEnvironmentVariables.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedOauthClientCredentialsEnvironmentVariables.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/Optional.cs b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/Optional.cs index 6cdd5c561723..c0e9ff805945 100644 --- a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/Optional.cs +++ b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/OptionalAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/OptionalAttribute.cs index 91e78f065512..ee544cf833f0 100644 --- a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedOauthClientCredentialsEnvironmentVariables.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/QueryStringBuilder.cs b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/QueryStringBuilder.cs index d668dd37051b..8849754db2f7 100644 --- a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/SeedOauthClientCredentialsEnvironmentVariables.csproj b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/SeedOauthClientCredentialsEnvironmentVariables.csproj index 0e444d21e222..51e91499d577 100644 --- a/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/SeedOauthClientCredentialsEnvironmentVariables.csproj +++ b/seed/csharp-sdk/oauth-client-credentials-environment-variables/src/SeedOauthClientCredentialsEnvironmentVariables/SeedOauthClientCredentialsEnvironmentVariables.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/oauth-client-credentials-environment-variables/fern + https://github.com/oauth-client-credentials-environment-variables/fern + git true diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/README.md b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/README.md index 7b97a85d849c..0c5053dd91b8 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/README.md +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -110,7 +113,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -123,7 +126,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -153,7 +156,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenWithClientCredentialsAsync(...); +var parsedData = await client.Auth.GetTokenWithClientCredentialsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth.Test/Utils/OptionalComparer.cs index 0dc76d8e6f61..931da4e99a3d 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/Extensions.cs b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/Extensions.cs index a62a0a373582..33e62c9ccc38 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/Extensions.cs +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/NullableAttribute.cs index b923587bd41a..87230d3ba48e 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedOauthClientCredentialsMandatoryAuth.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedOauthClientCredentialsMandatoryAuth.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/Optional.cs b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/Optional.cs index 0aa2325d6d39..231e7919c57d 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/Optional.cs +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/OptionalAttribute.cs index 0c0182d002a0..4560d2d32b99 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedOauthClientCredentialsMandatoryAuth.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/QueryStringBuilder.cs index b1a248256d29..7ebddce2ef56 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/SeedOauthClientCredentialsMandatoryAuth.csproj b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/SeedOauthClientCredentialsMandatoryAuth.csproj index cc0b694a2d51..bfcab926c399 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/SeedOauthClientCredentialsMandatoryAuth.csproj +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/src/SeedOauthClientCredentialsMandatoryAuth/SeedOauthClientCredentialsMandatoryAuth.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/oauth-client-credentials-mandatory-auth/fern + https://github.com/oauth-client-credentials-mandatory-auth/fern + git true diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/README.md b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/README.md index 6fba1011559a..035d7d44b576 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/README.md +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -112,7 +115,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -125,7 +128,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -155,7 +158,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenWithClientCredentialsAsync(...); +var parsedData = await client.Auth.GetTokenWithClientCredentialsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth.Test/Utils/OptionalComparer.cs index 0dc76d8e6f61..931da4e99a3d 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/Extensions.cs b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/Extensions.cs index a62a0a373582..33e62c9ccc38 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/Extensions.cs +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/NullableAttribute.cs index b923587bd41a..87230d3ba48e 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedOauthClientCredentialsMandatoryAuth.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedOauthClientCredentialsMandatoryAuth.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/Optional.cs b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/Optional.cs index 0aa2325d6d39..231e7919c57d 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/Optional.cs +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/OptionalAttribute.cs index 0c0182d002a0..4560d2d32b99 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedOauthClientCredentialsMandatoryAuth.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/QueryStringBuilder.cs index b1a248256d29..7ebddce2ef56 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/SeedOauthClientCredentialsMandatoryAuth.csproj b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/SeedOauthClientCredentialsMandatoryAuth.csproj index cc0b694a2d51..bfcab926c399 100644 --- a/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/SeedOauthClientCredentialsMandatoryAuth.csproj +++ b/seed/csharp-sdk/oauth-client-credentials-mandatory-auth/unified-client-options/src/SeedOauthClientCredentialsMandatoryAuth/SeedOauthClientCredentialsMandatoryAuth.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/oauth-client-credentials-mandatory-auth/fern + https://github.com/oauth-client-credentials-mandatory-auth/fern + git true diff --git a/seed/csharp-sdk/oauth-client-credentials-nested-root/README.md b/seed/csharp-sdk/oauth-client-credentials-nested-root/README.md index c9ab5908c60d..f19202899a09 100644 --- a/seed/csharp-sdk/oauth-client-credentials-nested-root/README.md +++ b/seed/csharp-sdk/oauth-client-credentials-nested-root/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -111,7 +114,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -124,7 +127,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -154,7 +157,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenAsync(...); +var parsedData = await client.Auth.GetTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs index 9592099f4ada..7e1d89d6a924 100644 --- a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/Extensions.cs b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/Extensions.cs index 05db0ec05881..3dfb846f50ed 100644 --- a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/Extensions.cs +++ b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/NullableAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/NullableAttribute.cs index 20f4b72c9468..8acacb080e25 100644 --- a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedOauthClientCredentials.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedOauthClientCredentials.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/Optional.cs b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/Optional.cs index 25fc6d0298dd..74130f54fcb0 100644 --- a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/Optional.cs +++ b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs index 825eb2f3d589..83dbc98f0b3e 100644 --- a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedOauthClientCredentials.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs index 12ec33f1a6df..a2f0a7457051 100644 --- a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj index ef405f7d4aa9..c357dc99dd68 100644 --- a/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj +++ b/seed/csharp-sdk/oauth-client-credentials-nested-root/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/oauth-client-credentials-nested-root/fern + https://github.com/oauth-client-credentials-nested-root/fern + git true diff --git a/seed/csharp-sdk/oauth-client-credentials-openapi/README.md b/seed/csharp-sdk/oauth-client-credentials-openapi/README.md index 5a81bb750f10..f55d59cfb485 100644 --- a/seed/csharp-sdk/oauth-client-credentials-openapi/README.md +++ b/seed/csharp-sdk/oauth-client-credentials-openapi/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Identity.GetTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Identity.GetTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Identity.GetTokenAsync(...); +var parsedData = await client.Identity.GetTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/SeedApi.csproj index bef1c3521a4b..e5c023ff3691 100644 --- a/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/oauth-client-credentials-openapi/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/oauth-client-credentials-openapi/fern + https://github.com/oauth-client-credentials-openapi/fern + git true diff --git a/seed/csharp-sdk/oauth-client-credentials-reference/README.md b/seed/csharp-sdk/oauth-client-credentials-reference/README.md index f3f43d9ed971..6b7f3cbff414 100644 --- a/seed/csharp-sdk/oauth-client-credentials-reference/README.md +++ b/seed/csharp-sdk/oauth-client-credentials-reference/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenAsync(...); +var parsedData = await client.Auth.GetTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference.Test/Utils/OptionalComparer.cs index 863c2ff44496..e042d4860d29 100644 --- a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/Extensions.cs b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/Extensions.cs index 5cc66982742d..d4fe7ce6d9d8 100644 --- a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/Extensions.cs +++ b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/NullableAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/NullableAttribute.cs index f520a21e344c..9f758400359f 100644 --- a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedOauthClientCredentialsReference.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedOauthClientCredentialsReference.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/Optional.cs b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/Optional.cs index 080dfecf2ae1..764cc9ca9249 100644 --- a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/Optional.cs +++ b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/OptionalAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/OptionalAttribute.cs index beabb02b3249..38ff84d844ae 100644 --- a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedOauthClientCredentialsReference.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/QueryStringBuilder.cs b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/QueryStringBuilder.cs index 9c20ab98c3c3..c0e1d4df6bec 100644 --- a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/SeedOauthClientCredentialsReference.csproj b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/SeedOauthClientCredentialsReference.csproj index 7f421c2f96b4..d831228d964b 100644 --- a/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/SeedOauthClientCredentialsReference.csproj +++ b/seed/csharp-sdk/oauth-client-credentials-reference/src/SeedOauthClientCredentialsReference/SeedOauthClientCredentialsReference.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/oauth-client-credentials-reference/fern + https://github.com/oauth-client-credentials-reference/fern + git true diff --git a/seed/csharp-sdk/oauth-client-credentials-with-variables/README.md b/seed/csharp-sdk/oauth-client-credentials-with-variables/README.md index a5b21410e251..c8f622723f8e 100644 --- a/seed/csharp-sdk/oauth-client-credentials-with-variables/README.md +++ b/seed/csharp-sdk/oauth-client-credentials-with-variables/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -110,7 +113,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -123,7 +126,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -153,7 +156,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenWithClientCredentialsAsync(...); +var parsedData = await client.Auth.GetTokenWithClientCredentialsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables.Test/Utils/OptionalComparer.cs index 38fc78186e75..7477c89c892e 100644 --- a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/Extensions.cs b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/Extensions.cs index 71b3d9a8c619..5291f5395ffc 100644 --- a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/Extensions.cs +++ b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/NullableAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/NullableAttribute.cs index 9144d7d10c62..1c0fea27102e 100644 --- a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedOauthClientCredentialsWithVariables.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedOauthClientCredentialsWithVariables.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/Optional.cs b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/Optional.cs index e90353da9d87..4b8d67cf5c6e 100644 --- a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/Optional.cs +++ b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/OptionalAttribute.cs b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/OptionalAttribute.cs index 65ab0ae9aee6..422e4e120d06 100644 --- a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedOauthClientCredentialsWithVariables.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/QueryStringBuilder.cs b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/QueryStringBuilder.cs index 96d1053f0101..2f68377abbe8 100644 --- a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/SeedOauthClientCredentialsWithVariables.csproj b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/SeedOauthClientCredentialsWithVariables.csproj index 32618a4bebed..40efcacabec7 100644 --- a/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/SeedOauthClientCredentialsWithVariables.csproj +++ b/seed/csharp-sdk/oauth-client-credentials-with-variables/src/SeedOauthClientCredentialsWithVariables/SeedOauthClientCredentialsWithVariables.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/oauth-client-credentials-with-variables/fern + https://github.com/oauth-client-credentials-with-variables/fern + git true diff --git a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/README.md b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/README.md index 1b3b892e8b2b..f76ad8a597b0 100644 --- a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/README.md +++ b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -110,7 +113,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -123,7 +126,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -153,7 +156,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenWithClientCredentialsAsync(...); +var parsedData = await client.Auth.GetTokenWithClientCredentialsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs index 9592099f4ada..7e1d89d6a924 100644 --- a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/Extensions.cs b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/Extensions.cs index 05db0ec05881..3dfb846f50ed 100644 --- a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/Extensions.cs +++ b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/NullableAttribute.cs b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/NullableAttribute.cs index 20f4b72c9468..8acacb080e25 100644 --- a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedOauthClientCredentials.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedOauthClientCredentials.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/Optional.cs b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/Optional.cs index 25fc6d0298dd..74130f54fcb0 100644 --- a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/Optional.cs +++ b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs index 825eb2f3d589..83dbc98f0b3e 100644 --- a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedOauthClientCredentials.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs index 12ec33f1a6df..a2f0a7457051 100644 --- a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj index be88ed5c5e18..969525e5ead9 100644 --- a/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj +++ b/seed/csharp-sdk/oauth-client-credentials/include-exception-handler/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/oauth-client-credentials/fern + https://github.com/oauth-client-credentials/fern + git true diff --git a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/README.md b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/README.md index 1b3b892e8b2b..f76ad8a597b0 100644 --- a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/README.md +++ b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -110,7 +113,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -123,7 +126,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -153,7 +156,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenWithClientCredentialsAsync(...); +var parsedData = await client.Auth.GetTokenWithClientCredentialsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs index 9592099f4ada..7e1d89d6a924 100644 --- a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/Extensions.cs b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/Extensions.cs index 05db0ec05881..3dfb846f50ed 100644 --- a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/Extensions.cs +++ b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/NullableAttribute.cs b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/NullableAttribute.cs index 20f4b72c9468..8acacb080e25 100644 --- a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedOauthClientCredentials.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedOauthClientCredentials.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/Optional.cs b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/Optional.cs index 25fc6d0298dd..74130f54fcb0 100644 --- a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/Optional.cs +++ b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs index 825eb2f3d589..83dbc98f0b3e 100644 --- a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedOauthClientCredentials.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs index 12ec33f1a6df..a2f0a7457051 100644 --- a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj index be88ed5c5e18..969525e5ead9 100644 --- a/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj +++ b/seed/csharp-sdk/oauth-client-credentials/no-custom-config/src/SeedOauthClientCredentials/SeedOauthClientCredentials.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/oauth-client-credentials/fern + https://github.com/oauth-client-credentials/fern + git true diff --git a/seed/csharp-sdk/oauth-pkce/README.md b/seed/csharp-sdk/oauth-pkce/README.md index dea1ac183bf7..10aa934285d7 100644 --- a/seed/csharp-sdk/oauth-pkce/README.md +++ b/seed/csharp-sdk/oauth-pkce/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -112,7 +115,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Oauth.AuthorizeAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -125,7 +128,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Oauth.AuthorizeAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -155,7 +158,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Oauth.AuthorizeAsync(...); +var parsedData = await client.Oauth.AuthorizeAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce.Test/Utils/OptionalComparer.cs index 840a4f661948..08d7538a144d 100644 --- a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/Extensions.cs b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/Extensions.cs index c11062cc3672..5a2b8fcfa3e9 100644 --- a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/Extensions.cs +++ b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/NullableAttribute.cs b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/NullableAttribute.cs index a3c4a7e08ff3..48586c5f7392 100644 --- a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedOauthPkce.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedOauthPkce.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/Optional.cs b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/Optional.cs index d65110206de7..52c4e2f4069a 100644 --- a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/Optional.cs +++ b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/OptionalAttribute.cs b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/OptionalAttribute.cs index b2119269b8a7..585f4d0a812e 100644 --- a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedOauthPkce.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/QueryStringBuilder.cs b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/QueryStringBuilder.cs index 5ec92db7d5a5..31aa4f2e4834 100644 --- a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/SeedOauthPkce.csproj b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/SeedOauthPkce.csproj index 4e439219052b..6a981a739dc7 100644 --- a/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/SeedOauthPkce.csproj +++ b/seed/csharp-sdk/oauth-pkce/src/SeedOauthPkce/SeedOauthPkce.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/oauth-pkce/fern + https://github.com/oauth-pkce/fern + git true diff --git a/seed/csharp-sdk/object/src/SeedObject.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/object/src/SeedObject.Test/Utils/OptionalComparer.cs index cc24ed83b13d..35722da95f75 100644 --- a/seed/csharp-sdk/object/src/SeedObject.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/object/src/SeedObject.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/object/src/SeedObject/Core/Extensions.cs b/seed/csharp-sdk/object/src/SeedObject/Core/Extensions.cs index f1b0f52b6193..201231905e6a 100644 --- a/seed/csharp-sdk/object/src/SeedObject/Core/Extensions.cs +++ b/seed/csharp-sdk/object/src/SeedObject/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/object/src/SeedObject/Core/NullableAttribute.cs b/seed/csharp-sdk/object/src/SeedObject/Core/NullableAttribute.cs index d04139e265f6..a306f72516ee 100644 --- a/seed/csharp-sdk/object/src/SeedObject/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/object/src/SeedObject/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedObject.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedObject.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/object/src/SeedObject/Core/Optional.cs b/seed/csharp-sdk/object/src/SeedObject/Core/Optional.cs index ac97764fc8b4..46e6d01a74e0 100644 --- a/seed/csharp-sdk/object/src/SeedObject/Core/Optional.cs +++ b/seed/csharp-sdk/object/src/SeedObject/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/object/src/SeedObject/Core/OptionalAttribute.cs b/seed/csharp-sdk/object/src/SeedObject/Core/OptionalAttribute.cs index c74fcf21c2ff..6655c6ea4e76 100644 --- a/seed/csharp-sdk/object/src/SeedObject/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/object/src/SeedObject/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedObject.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/object/src/SeedObject/Core/QueryStringBuilder.cs b/seed/csharp-sdk/object/src/SeedObject/Core/QueryStringBuilder.cs index fc73bd7f39ad..33b8c3ee48e6 100644 --- a/seed/csharp-sdk/object/src/SeedObject/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/object/src/SeedObject/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/object/src/SeedObject/SeedObject.csproj b/seed/csharp-sdk/object/src/SeedObject/SeedObject.csproj index 58dc8013946f..92291fd9f4e3 100644 --- a/seed/csharp-sdk/object/src/SeedObject/SeedObject.csproj +++ b/seed/csharp-sdk/object/src/SeedObject/SeedObject.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/object/fern + https://github.com/object/fern + git true diff --git a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports.Test/Utils/OptionalComparer.cs index cf6195a8770a..8b8956eef4c9 100644 --- a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/Extensions.cs b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/Extensions.cs index 697c1d38a261..7fc85b6ead8b 100644 --- a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/Extensions.cs +++ b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/NullableAttribute.cs b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/NullableAttribute.cs index 06235e7c31f2..d304a55edad0 100644 --- a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedObjectsWithImports.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedObjectsWithImports.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/Optional.cs b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/Optional.cs index cd76df928c38..2452ec08fd95 100644 --- a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/Optional.cs +++ b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/OptionalAttribute.cs b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/OptionalAttribute.cs index f0faf5fef286..70f8786ad0f1 100644 --- a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedObjectsWithImports.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/QueryStringBuilder.cs b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/QueryStringBuilder.cs index a443579b2bdd..857147d95b67 100644 --- a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/SeedObjectsWithImports.csproj b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/SeedObjectsWithImports.csproj index d00a1344117e..a19818fed7b5 100644 --- a/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/SeedObjectsWithImports.csproj +++ b/seed/csharp-sdk/objects-with-imports/src/SeedObjectsWithImports/SeedObjectsWithImports.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/objects-with-imports/fern + https://github.com/objects-with-imports/fern + git true diff --git a/seed/csharp-sdk/openapi-path-param-body-collision/README.md b/seed/csharp-sdk/openapi-path-param-body-collision/README.md index 55dd32642cdb..5bfb2139acd3 100644 --- a/seed/csharp-sdk/openapi-path-param-body-collision/README.md +++ b/seed/csharp-sdk/openapi-path-param-body-collision/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -124,7 +127,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.UpdateProfileIdentifierAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -137,7 +140,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.UpdateProfileIdentifierAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -167,7 +170,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.UpdateProfileIdentifierAsync(...); +var parsedData = await client.UpdateProfileIdentifierAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/SeedApi.csproj index 04778b57e721..523b23767012 100644 --- a/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/openapi-path-param-body-collision/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/openapi-path-param-body-collision/fern + https://github.com/openapi-path-param-body-collision/fern + git true diff --git a/seed/csharp-sdk/openapi-request-body-ref/README.md b/seed/csharp-sdk/openapi-request-body-ref/README.md index 8e3c6e6e7a22..29226c71bc82 100644 --- a/seed/csharp-sdk/openapi-request-body-ref/README.md +++ b/seed/csharp-sdk/openapi-request-body-ref/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -102,7 +105,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Vendor.CreateVendorAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -115,7 +118,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Vendor.CreateVendorAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -145,7 +148,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Vendor.CreateVendorAsync(...); +var parsedData = await client.Vendor.CreateVendorAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/SeedApi.csproj index 2f76b3bdb9ae..fa696d5d1f34 100644 --- a/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/openapi-request-body-ref/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/openapi-request-body-ref/fern + https://github.com/openapi-request-body-ref/fern + git true diff --git a/seed/csharp-sdk/openapi-subtitle/README.md b/seed/csharp-sdk/openapi-subtitle/README.md index 4dd01449a480..e4b4ed6d5ef8 100644 --- a/seed/csharp-sdk/openapi-subtitle/README.md +++ b/seed/csharp-sdk/openapi-subtitle/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.ListPlantsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.ListPlantsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.ListPlantsAsync(...); +var parsedData = await client.ListPlantsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/openapi-subtitle/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/openapi-subtitle/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/openapi-subtitle/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/openapi-subtitle/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/openapi-subtitle/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/openapi-subtitle/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/openapi-subtitle/src/SeedApi/SeedApi.csproj index 2035158d1a03..5bdba1b5e87f 100644 --- a/seed/csharp-sdk/openapi-subtitle/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/openapi-subtitle/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/openapi-subtitle/fern + https://github.com/openapi-subtitle/fern + git true diff --git a/seed/csharp-sdk/optional/no-custom-config/README.md b/seed/csharp-sdk/optional/no-custom-config/README.md index 434cd6578a0c..c9a0de6f4eaa 100644 --- a/seed/csharp-sdk/optional/no-custom-config/README.md +++ b/seed/csharp-sdk/optional/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Optional.SendOptionalBodyAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Optional.SendOptionalBodyAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Optional.SendOptionalBodyAsync(...); +var parsedData = await client.Optional.SendOptionalBodyAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports.Test/Utils/OptionalComparer.cs index cf6195a8770a..8b8956eef4c9 100644 --- a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/Extensions.cs b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/Extensions.cs index 697c1d38a261..7fc85b6ead8b 100644 --- a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/Extensions.cs +++ b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/NullableAttribute.cs b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/NullableAttribute.cs index 06235e7c31f2..d304a55edad0 100644 --- a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedObjectsWithImports.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedObjectsWithImports.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/Optional.cs b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/Optional.cs index cd76df928c38..2452ec08fd95 100644 --- a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/Optional.cs +++ b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/OptionalAttribute.cs b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/OptionalAttribute.cs index f0faf5fef286..70f8786ad0f1 100644 --- a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedObjectsWithImports.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/QueryStringBuilder.cs b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/QueryStringBuilder.cs index a443579b2bdd..857147d95b67 100644 --- a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/SeedObjectsWithImports.csproj b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/SeedObjectsWithImports.csproj index 46736c7c2d3d..104084a644f0 100644 --- a/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/SeedObjectsWithImports.csproj +++ b/seed/csharp-sdk/optional/no-custom-config/src/SeedObjectsWithImports/SeedObjectsWithImports.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/optional/fern + https://github.com/optional/fern + git true diff --git a/seed/csharp-sdk/optional/simplify-object-dictionaries/README.md b/seed/csharp-sdk/optional/simplify-object-dictionaries/README.md index 434cd6578a0c..c9a0de6f4eaa 100644 --- a/seed/csharp-sdk/optional/simplify-object-dictionaries/README.md +++ b/seed/csharp-sdk/optional/simplify-object-dictionaries/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Optional.SendOptionalBodyAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Optional.SendOptionalBodyAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Optional.SendOptionalBodyAsync(...); +var parsedData = await client.Optional.SendOptionalBodyAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports.Test/Utils/OptionalComparer.cs index cf6195a8770a..8b8956eef4c9 100644 --- a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/Extensions.cs b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/Extensions.cs index 697c1d38a261..7fc85b6ead8b 100644 --- a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/Extensions.cs +++ b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/NullableAttribute.cs b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/NullableAttribute.cs index 06235e7c31f2..d304a55edad0 100644 --- a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedObjectsWithImports.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedObjectsWithImports.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/Optional.cs b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/Optional.cs index cd76df928c38..2452ec08fd95 100644 --- a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/Optional.cs +++ b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/OptionalAttribute.cs b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/OptionalAttribute.cs index f0faf5fef286..70f8786ad0f1 100644 --- a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedObjectsWithImports.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/QueryStringBuilder.cs b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/QueryStringBuilder.cs index a443579b2bdd..857147d95b67 100644 --- a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/SeedObjectsWithImports.csproj b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/SeedObjectsWithImports.csproj index 46736c7c2d3d..104084a644f0 100644 --- a/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/SeedObjectsWithImports.csproj +++ b/seed/csharp-sdk/optional/simplify-object-dictionaries/src/SeedObjectsWithImports/SeedObjectsWithImports.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/optional/fern + https://github.com/optional/fern + git true diff --git a/seed/csharp-sdk/package-yml/README.md b/seed/csharp-sdk/package-yml/README.md index e103461e143d..8a3c654505de 100644 --- a/seed/csharp-sdk/package-yml/README.md +++ b/seed/csharp-sdk/package-yml/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.EchoAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.EchoAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.EchoAsync(...); +var parsedData = await client.EchoAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/package-yml/src/SeedPackageYml.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/package-yml/src/SeedPackageYml.Test/Utils/OptionalComparer.cs index 47dd342b6eca..afcd6344d8e5 100644 --- a/seed/csharp-sdk/package-yml/src/SeedPackageYml.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/package-yml/src/SeedPackageYml.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/Extensions.cs b/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/Extensions.cs index 7499a9d703bb..d10f25ac9ae9 100644 --- a/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/Extensions.cs +++ b/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/NullableAttribute.cs b/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/NullableAttribute.cs index 3771fe7baccd..2567f4afb2a1 100644 --- a/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedPackageYml.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedPackageYml.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/Optional.cs b/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/Optional.cs index 0b6430ee3fd1..cec189a7f6a5 100644 --- a/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/Optional.cs +++ b/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/OptionalAttribute.cs b/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/OptionalAttribute.cs index 9d8d2ad00217..f37858f7a6ca 100644 --- a/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedPackageYml.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/QueryStringBuilder.cs b/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/QueryStringBuilder.cs index e8e24dc8516c..b10cdd42e9b3 100644 --- a/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/package-yml/src/SeedPackageYml/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/package-yml/src/SeedPackageYml/SeedPackageYml.csproj b/seed/csharp-sdk/package-yml/src/SeedPackageYml/SeedPackageYml.csproj index 587ec027f4d6..f7e4904733e0 100644 --- a/seed/csharp-sdk/package-yml/src/SeedPackageYml/SeedPackageYml.csproj +++ b/seed/csharp-sdk/package-yml/src/SeedPackageYml/SeedPackageYml.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/package-yml/fern + https://github.com/package-yml/fern + git true diff --git a/seed/csharp-sdk/pagination-custom/README.md b/seed/csharp-sdk/pagination-custom/README.md index 7df7f4b01aa2..ae188099f70a 100644 --- a/seed/csharp-sdk/pagination-custom/README.md +++ b/seed/csharp-sdk/pagination-custom/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -127,7 +130,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Users.ListWithCustomPagerAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -140,7 +143,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Users.ListWithCustomPagerAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -170,7 +173,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Users.ListWithCustomPagerAsync(...); +var parsedData = await client.Users.ListWithCustomPagerAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/pagination-custom/src/SeedPagination.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/pagination-custom/src/SeedPagination.Test/Utils/OptionalComparer.cs index 6e5923eea7d5..0afc4fef175f 100644 --- a/seed/csharp-sdk/pagination-custom/src/SeedPagination.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/pagination-custom/src/SeedPagination.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/Extensions.cs b/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/Extensions.cs index b592527e088a..47bd121ec865 100644 --- a/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/Extensions.cs +++ b/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/NullableAttribute.cs b/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/NullableAttribute.cs index ec57e1a8443c..baeb7f9c9d64 100644 --- a/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedPagination.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedPagination.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/Optional.cs b/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/Optional.cs index 2363917968f9..361f1cec5c3b 100644 --- a/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/Optional.cs +++ b/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/OptionalAttribute.cs b/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/OptionalAttribute.cs index c60c1d32614c..aba47aee2b17 100644 --- a/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedPagination.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/QueryStringBuilder.cs b/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/QueryStringBuilder.cs index d4f0a8cc4e29..341dc8c4baa2 100644 --- a/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/pagination-custom/src/SeedPagination/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/pagination-custom/src/SeedPagination/SeedPagination.csproj b/seed/csharp-sdk/pagination-custom/src/SeedPagination/SeedPagination.csproj index bd41a838c5ff..4d11b1d7169a 100644 --- a/seed/csharp-sdk/pagination-custom/src/SeedPagination/SeedPagination.csproj +++ b/seed/csharp-sdk/pagination-custom/src/SeedPagination/SeedPagination.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/pagination-custom/fern + https://github.com/pagination-custom/fern + git true diff --git a/seed/csharp-sdk/pagination-uri-path/README.md b/seed/csharp-sdk/pagination-uri-path/README.md index fcfaddbbab6c..52595f5247fa 100644 --- a/seed/csharp-sdk/pagination-uri-path/README.md +++ b/seed/csharp-sdk/pagination-uri-path/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Users.ListWithUriPaginationAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Users.ListWithUriPaginationAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Users.ListWithUriPaginationAsync(...); +var parsedData = await client.Users.ListWithUriPaginationAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath.Test/Utils/OptionalComparer.cs index be71d9e637a8..c37975b6b4f1 100644 --- a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/Extensions.cs b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/Extensions.cs index eba4c9cb7579..9e3a5054dead 100644 --- a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/Extensions.cs +++ b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/NullableAttribute.cs b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/NullableAttribute.cs index fc0746c35d23..723645d7ca15 100644 --- a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedPaginationUriPath.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedPaginationUriPath.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/Optional.cs b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/Optional.cs index a816818ce29d..497f8507c1e8 100644 --- a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/Optional.cs +++ b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/OptionalAttribute.cs b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/OptionalAttribute.cs index acec084214db..ec9b07f52aa0 100644 --- a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedPaginationUriPath.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/QueryStringBuilder.cs b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/QueryStringBuilder.cs index 65c9e7fab3a7..81ca888b786e 100644 --- a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/SeedPaginationUriPath.csproj b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/SeedPaginationUriPath.csproj index 48ff60ab838c..09eef75e4264 100644 --- a/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/SeedPaginationUriPath.csproj +++ b/seed/csharp-sdk/pagination-uri-path/src/SeedPaginationUriPath/SeedPaginationUriPath.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/pagination-uri-path/fern + https://github.com/pagination-uri-path/fern + git true diff --git a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/README.md b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/README.md index 2aca1dab01ce..8613e4607b49 100644 --- a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/README.md +++ b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -148,7 +151,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Complex.SearchAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -161,7 +164,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Complex.SearchAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -191,7 +194,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Complex.SearchAsync(...); +var parsedData = await client.Complex.SearchAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination.Test/Utils/OptionalComparer.cs index 6e5923eea7d5..0afc4fef175f 100644 --- a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/Extensions.cs b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/Extensions.cs index b592527e088a..47bd121ec865 100644 --- a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/Extensions.cs +++ b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/NullableAttribute.cs b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/NullableAttribute.cs index ec57e1a8443c..baeb7f9c9d64 100644 --- a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedPagination.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedPagination.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/Optional.cs b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/Optional.cs index 2363917968f9..361f1cec5c3b 100644 --- a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/Optional.cs +++ b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/OptionalAttribute.cs b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/OptionalAttribute.cs index c60c1d32614c..aba47aee2b17 100644 --- a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedPagination.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/QueryStringBuilder.cs b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/QueryStringBuilder.cs index d4f0a8cc4e29..341dc8c4baa2 100644 --- a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/SeedPagination.csproj b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/SeedPagination.csproj index d84e585f2cc8..10bdbd6ed9f5 100644 --- a/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/SeedPagination.csproj +++ b/seed/csharp-sdk/pagination/custom-pager-with-exception-handler/src/SeedPagination/SeedPagination.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/pagination/fern + https://github.com/pagination/fern + git true diff --git a/seed/csharp-sdk/pagination/custom-pager/README.md b/seed/csharp-sdk/pagination/custom-pager/README.md index 2aca1dab01ce..8613e4607b49 100644 --- a/seed/csharp-sdk/pagination/custom-pager/README.md +++ b/seed/csharp-sdk/pagination/custom-pager/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -148,7 +151,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Complex.SearchAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -161,7 +164,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Complex.SearchAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -191,7 +194,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Complex.SearchAsync(...); +var parsedData = await client.Complex.SearchAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination.Test/Utils/OptionalComparer.cs index 6e5923eea7d5..0afc4fef175f 100644 --- a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/Extensions.cs b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/Extensions.cs index b592527e088a..47bd121ec865 100644 --- a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/Extensions.cs +++ b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/NullableAttribute.cs b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/NullableAttribute.cs index ec57e1a8443c..baeb7f9c9d64 100644 --- a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedPagination.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedPagination.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/Optional.cs b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/Optional.cs index 2363917968f9..361f1cec5c3b 100644 --- a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/Optional.cs +++ b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/OptionalAttribute.cs b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/OptionalAttribute.cs index c60c1d32614c..aba47aee2b17 100644 --- a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedPagination.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/QueryStringBuilder.cs b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/QueryStringBuilder.cs index d4f0a8cc4e29..341dc8c4baa2 100644 --- a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/SeedPagination.csproj b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/SeedPagination.csproj index d84e585f2cc8..10bdbd6ed9f5 100644 --- a/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/SeedPagination.csproj +++ b/seed/csharp-sdk/pagination/custom-pager/src/SeedPagination/SeedPagination.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/pagination/fern + https://github.com/pagination/fern + git true diff --git a/seed/csharp-sdk/pagination/no-custom-config/README.md b/seed/csharp-sdk/pagination/no-custom-config/README.md index 2aca1dab01ce..8613e4607b49 100644 --- a/seed/csharp-sdk/pagination/no-custom-config/README.md +++ b/seed/csharp-sdk/pagination/no-custom-config/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -148,7 +151,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Complex.SearchAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -161,7 +164,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Complex.SearchAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -191,7 +194,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Complex.SearchAsync(...); +var parsedData = await client.Complex.SearchAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination.Test/Utils/OptionalComparer.cs index 6e5923eea7d5..0afc4fef175f 100644 --- a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/Extensions.cs b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/Extensions.cs index b592527e088a..47bd121ec865 100644 --- a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/Extensions.cs +++ b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/NullableAttribute.cs b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/NullableAttribute.cs index ec57e1a8443c..baeb7f9c9d64 100644 --- a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedPagination.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedPagination.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/Optional.cs b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/Optional.cs index 2363917968f9..361f1cec5c3b 100644 --- a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/Optional.cs +++ b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/OptionalAttribute.cs b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/OptionalAttribute.cs index c60c1d32614c..aba47aee2b17 100644 --- a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedPagination.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/QueryStringBuilder.cs b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/QueryStringBuilder.cs index d4f0a8cc4e29..341dc8c4baa2 100644 --- a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/SeedPagination.csproj b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/SeedPagination.csproj index d84e585f2cc8..10bdbd6ed9f5 100644 --- a/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/SeedPagination.csproj +++ b/seed/csharp-sdk/pagination/no-custom-config/src/SeedPagination/SeedPagination.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/pagination/fern + https://github.com/pagination/fern + git true diff --git a/seed/csharp-sdk/pagination/page-index-semantics/README.md b/seed/csharp-sdk/pagination/page-index-semantics/README.md index 2aca1dab01ce..8613e4607b49 100644 --- a/seed/csharp-sdk/pagination/page-index-semantics/README.md +++ b/seed/csharp-sdk/pagination/page-index-semantics/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -148,7 +151,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Complex.SearchAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -161,7 +164,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Complex.SearchAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -191,7 +194,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Complex.SearchAsync(...); +var parsedData = await client.Complex.SearchAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination.Test/Utils/OptionalComparer.cs index 6e5923eea7d5..0afc4fef175f 100644 --- a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/Extensions.cs b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/Extensions.cs index b592527e088a..47bd121ec865 100644 --- a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/Extensions.cs +++ b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/NullableAttribute.cs b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/NullableAttribute.cs index ec57e1a8443c..baeb7f9c9d64 100644 --- a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedPagination.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedPagination.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/Optional.cs b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/Optional.cs index 2363917968f9..361f1cec5c3b 100644 --- a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/Optional.cs +++ b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/OptionalAttribute.cs b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/OptionalAttribute.cs index c60c1d32614c..aba47aee2b17 100644 --- a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedPagination.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/QueryStringBuilder.cs b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/QueryStringBuilder.cs index d4f0a8cc4e29..341dc8c4baa2 100644 --- a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/SeedPagination.csproj b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/SeedPagination.csproj index d84e585f2cc8..10bdbd6ed9f5 100644 --- a/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/SeedPagination.csproj +++ b/seed/csharp-sdk/pagination/page-index-semantics/src/SeedPagination/SeedPagination.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/pagination/fern + https://github.com/pagination/fern + git true diff --git a/seed/csharp-sdk/path-parameters/no-custom-config/README.md b/seed/csharp-sdk/path-parameters/no-custom-config/README.md index 0598665054cb..4151bd2f9799 100644 --- a/seed/csharp-sdk/path-parameters/no-custom-config/README.md +++ b/seed/csharp-sdk/path-parameters/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -108,7 +111,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -121,7 +124,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -151,7 +154,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.CreateUserAsync(...); +var parsedData = await client.User.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters.Test/Utils/OptionalComparer.cs index 4c3938d241bd..8ebb26b9990a 100644 --- a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/Extensions.cs b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/Extensions.cs index 93daf33473b4..295906a45f80 100644 --- a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/Extensions.cs +++ b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/NullableAttribute.cs b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/NullableAttribute.cs index ead38155e76c..68571a1ae638 100644 --- a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedPathParameters.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedPathParameters.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/Optional.cs b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/Optional.cs index 9ba8a05c076d..a20ef8a4be44 100644 --- a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/Optional.cs +++ b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/OptionalAttribute.cs b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/OptionalAttribute.cs index 5118fe4056fc..2c9a31a90c7c 100644 --- a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedPathParameters.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/QueryStringBuilder.cs b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/QueryStringBuilder.cs index 7fa889c85534..3e092dfb3a47 100644 --- a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/SeedPathParameters.csproj b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/SeedPathParameters.csproj index 616832d9bf15..d780e5ec0cd8 100644 --- a/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/SeedPathParameters.csproj +++ b/seed/csharp-sdk/path-parameters/no-custom-config/src/SeedPathParameters/SeedPathParameters.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/path-parameters/fern + https://github.com/path-parameters/fern + git true diff --git a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/README.md b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/README.md index 0598665054cb..4151bd2f9799 100644 --- a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/README.md +++ b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -108,7 +111,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -121,7 +124,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -151,7 +154,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.CreateUserAsync(...); +var parsedData = await client.User.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters.Test/Utils/OptionalComparer.cs index 4c3938d241bd..8ebb26b9990a 100644 --- a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/Extensions.cs b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/Extensions.cs index 93daf33473b4..295906a45f80 100644 --- a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/Extensions.cs +++ b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/NullableAttribute.cs b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/NullableAttribute.cs index ead38155e76c..68571a1ae638 100644 --- a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedPathParameters.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedPathParameters.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/Optional.cs b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/Optional.cs index 9ba8a05c076d..a20ef8a4be44 100644 --- a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/Optional.cs +++ b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/OptionalAttribute.cs b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/OptionalAttribute.cs index 5118fe4056fc..2c9a31a90c7c 100644 --- a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedPathParameters.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/QueryStringBuilder.cs b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/QueryStringBuilder.cs index 7fa889c85534..3e092dfb3a47 100644 --- a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/SeedPathParameters.csproj b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/SeedPathParameters.csproj index 616832d9bf15..d780e5ec0cd8 100644 --- a/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/SeedPathParameters.csproj +++ b/seed/csharp-sdk/path-parameters/no-inline-path-parameters/src/SeedPathParameters/SeedPathParameters.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/path-parameters/fern + https://github.com/path-parameters/fern + git true diff --git a/seed/csharp-sdk/plain-text/README.md b/seed/csharp-sdk/plain-text/README.md index 3c1e8151b7b0..373d151432f8 100644 --- a/seed/csharp-sdk/plain-text/README.md +++ b/seed/csharp-sdk/plain-text/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.GetTextAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.GetTextAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.GetTextAsync(...); +var parsedData = await client.Service.GetTextAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/plain-text/src/SeedPlainText.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/plain-text/src/SeedPlainText.Test/Utils/OptionalComparer.cs index ca9a15c04df1..4ba19e7f2593 100644 --- a/seed/csharp-sdk/plain-text/src/SeedPlainText.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/plain-text/src/SeedPlainText.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/Extensions.cs b/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/Extensions.cs index 10c6198e9af6..4bfe77d857ca 100644 --- a/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/Extensions.cs +++ b/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/NullableAttribute.cs b/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/NullableAttribute.cs index 3f811a6f183f..06971ef8bd8b 100644 --- a/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedPlainText.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedPlainText.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/Optional.cs b/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/Optional.cs index b6c283c27f3d..18359dc4d443 100644 --- a/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/Optional.cs +++ b/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/OptionalAttribute.cs b/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/OptionalAttribute.cs index ba444d389e4e..4e507582e0f5 100644 --- a/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedPlainText.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/QueryStringBuilder.cs b/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/QueryStringBuilder.cs index 9075a18694e5..b4d70c474175 100644 --- a/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/plain-text/src/SeedPlainText/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/plain-text/src/SeedPlainText/SeedPlainText.csproj b/seed/csharp-sdk/plain-text/src/SeedPlainText/SeedPlainText.csproj index 8ddfad22119c..d7fdcf4a2020 100644 --- a/seed/csharp-sdk/plain-text/src/SeedPlainText/SeedPlainText.csproj +++ b/seed/csharp-sdk/plain-text/src/SeedPlainText/SeedPlainText.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/plain-text/fern + https://github.com/plain-text/fern + git true diff --git a/seed/csharp-sdk/property-access/README.md b/seed/csharp-sdk/property-access/README.md index 5c0dac65d72a..04d90528b882 100644 --- a/seed/csharp-sdk/property-access/README.md +++ b/seed/csharp-sdk/property-access/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -114,7 +117,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreateUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -127,7 +130,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreateUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -157,7 +160,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreateUserAsync(...); +var parsedData = await client.CreateUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/property-access/src/SeedPropertyAccess.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/property-access/src/SeedPropertyAccess.Test/Utils/OptionalComparer.cs index a4fa23aefd62..99922ad1e306 100644 --- a/seed/csharp-sdk/property-access/src/SeedPropertyAccess.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/property-access/src/SeedPropertyAccess.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/Extensions.cs b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/Extensions.cs index fb62aa6f1516..93ba02b52024 100644 --- a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/Extensions.cs +++ b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/NullableAttribute.cs b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/NullableAttribute.cs index 0652925079a1..c79eaf7822b8 100644 --- a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedPropertyAccess.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedPropertyAccess.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/Optional.cs b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/Optional.cs index 7119e8cef4e4..d065ec61e2a8 100644 --- a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/Optional.cs +++ b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/OptionalAttribute.cs b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/OptionalAttribute.cs index 4a380a0d7bb1..943fb7b45e6f 100644 --- a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedPropertyAccess.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/QueryStringBuilder.cs b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/QueryStringBuilder.cs index 6dd21ff3ea3f..55778b462f49 100644 --- a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/SeedPropertyAccess.csproj b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/SeedPropertyAccess.csproj index e5773b099a9f..0749b2859672 100644 --- a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/SeedPropertyAccess.csproj +++ b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/SeedPropertyAccess.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/property-access/fern + https://github.com/property-access/fern + git true diff --git a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Types/UserOrAdminDiscriminated.cs b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Types/UserOrAdminDiscriminated.cs index 24aaedd08864..dee012fda670 100644 --- a/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Types/UserOrAdminDiscriminated.cs +++ b/seed/csharp-sdk/property-access/src/SeedPropertyAccess/Types/UserOrAdminDiscriminated.cs @@ -101,7 +101,7 @@ public SeedPropertyAccess.Admin AsAdmin() => : throw new global::System.Exception("UserOrAdminDiscriminated.Type is not 'admin'"); /// - /// Returns the value as a if is 'empty', otherwise throws an exception. + /// Returns the value as a if is 'empty', otherwise throws an exception. /// /// Thrown when is not 'empty'. public object? AsEmpty() => @@ -178,7 +178,7 @@ public bool TryAsAdmin(out SeedPropertyAccess.Admin? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsEmpty(out object? value) { diff --git a/seed/csharp-sdk/public-object/src/SeedPublicObject.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/public-object/src/SeedPublicObject.Test/Utils/OptionalComparer.cs index c06b351db935..24a65eb1d29c 100644 --- a/seed/csharp-sdk/public-object/src/SeedPublicObject.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/public-object/src/SeedPublicObject.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/Extensions.cs b/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/Extensions.cs index e011421e2506..6ef37accf8b9 100644 --- a/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/Extensions.cs +++ b/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/NullableAttribute.cs b/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/NullableAttribute.cs index afd2d9be0083..5211e9dbb8c4 100644 --- a/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedPublicObject.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedPublicObject.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/Optional.cs b/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/Optional.cs index bfcb16d22a12..e5da67b41f16 100644 --- a/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/Optional.cs +++ b/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/OptionalAttribute.cs b/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/OptionalAttribute.cs index 34791233778a..3cfe4087b4cb 100644 --- a/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedPublicObject.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/QueryStringBuilder.cs b/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/QueryStringBuilder.cs index b362ed35a9a5..93f3db718f8e 100644 --- a/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/public-object/src/SeedPublicObject/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/public-object/src/SeedPublicObject/SeedPublicObject.csproj b/seed/csharp-sdk/public-object/src/SeedPublicObject/SeedPublicObject.csproj index 3fe33dcb5c16..6363320b7ce9 100644 --- a/seed/csharp-sdk/public-object/src/SeedPublicObject/SeedPublicObject.csproj +++ b/seed/csharp-sdk/public-object/src/SeedPublicObject/SeedPublicObject.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/public-object/fern + https://github.com/public-object/fern + git true diff --git a/seed/csharp-sdk/query-param-name-conflict/README.md b/seed/csharp-sdk/query-param-name-conflict/README.md index 2e8cc25bb77c..46b324718d37 100644 --- a/seed/csharp-sdk/query-param-name-conflict/README.md +++ b/seed/csharp-sdk/query-param-name-conflict/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.BulkUpdateTasksAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.BulkUpdateTasksAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.BulkUpdateTasksAsync(...); +var parsedData = await client.BulkUpdateTasksAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/SeedApi.csproj index 85c6feecfbf7..80118477b96a 100644 --- a/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/query-param-name-conflict/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/query-param-name-conflict/fern + https://github.com/query-param-name-conflict/fern + git true diff --git a/seed/csharp-sdk/query-parameters-openapi-as-objects/README.md b/seed/csharp-sdk/query-parameters-openapi-as-objects/README.md index 9fe9df31f091..e8346b8cf5ae 100644 --- a/seed/csharp-sdk/query-parameters-openapi-as-objects/README.md +++ b/seed/csharp-sdk/query-parameters-openapi-as-objects/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -161,7 +164,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.SearchAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -174,7 +177,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.SearchAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -204,7 +207,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.SearchAsync(...); +var parsedData = await client.SearchAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/SeedApi.csproj index 83a9e5120055..199ba22a3425 100644 --- a/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/query-parameters-openapi-as-objects/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/query-parameters-openapi-as-objects/fern + https://github.com/query-parameters-openapi-as-objects/fern + git true diff --git a/seed/csharp-sdk/query-parameters-openapi/README.md b/seed/csharp-sdk/query-parameters-openapi/README.md index 456080ff8038..a4e75593491d 100644 --- a/seed/csharp-sdk/query-parameters-openapi/README.md +++ b/seed/csharp-sdk/query-parameters-openapi/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -161,7 +164,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.SearchAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -174,7 +177,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.SearchAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -204,7 +207,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.SearchAsync(...); +var parsedData = await client.SearchAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/SeedApi.csproj index bd420d73edc7..43d814a500be 100644 --- a/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/query-parameters-openapi/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/query-parameters-openapi/fern + https://github.com/query-parameters-openapi/fern + git true diff --git a/seed/csharp-sdk/query-parameters/README.md b/seed/csharp-sdk/query-parameters/README.md index 6c6b26682c0e..ec0717c7e02b 100644 --- a/seed/csharp-sdk/query-parameters/README.md +++ b/seed/csharp-sdk/query-parameters/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -154,7 +157,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.GetUsernameAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -167,7 +170,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.GetUsernameAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -197,7 +200,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.GetUsernameAsync(...); +var parsedData = await client.User.GetUsernameAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters.Test/Utils/OptionalComparer.cs index 39478ee8eddf..66f8bc9ede37 100644 --- a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/Extensions.cs b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/Extensions.cs index 19e3a369d758..b9e3995eacb2 100644 --- a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/Extensions.cs +++ b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/NullableAttribute.cs b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/NullableAttribute.cs index f6425a2b2307..e9908f790300 100644 --- a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedQueryParameters.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedQueryParameters.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/Optional.cs b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/Optional.cs index ff394847d5e7..647e474c1ecc 100644 --- a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/Optional.cs +++ b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/OptionalAttribute.cs b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/OptionalAttribute.cs index a1577f4ce9f4..dd70bc4ead9d 100644 --- a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedQueryParameters.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/QueryStringBuilder.cs b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/QueryStringBuilder.cs index 02ee5a2cbb8c..3b35d5391d83 100644 --- a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/SeedQueryParameters.csproj b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/SeedQueryParameters.csproj index a850d5ae4775..1bc68d02e789 100644 --- a/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/SeedQueryParameters.csproj +++ b/seed/csharp-sdk/query-parameters/src/SeedQueryParameters/SeedQueryParameters.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/query-parameters/fern + https://github.com/query-parameters/fern + git true diff --git a/seed/csharp-sdk/request-parameters/no-custom-config/README.md b/seed/csharp-sdk/request-parameters/no-custom-config/README.md index 03282a310b98..54a7d9e94bdd 100644 --- a/seed/csharp-sdk/request-parameters/no-custom-config/README.md +++ b/seed/csharp-sdk/request-parameters/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.CreateUsernameAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.CreateUsernameAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.CreateUsernameAsync(...); +var parsedData = await client.User.CreateUsernameAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters.Test/Utils/OptionalComparer.cs index d760d807d84a..9e9295bbd0ca 100644 --- a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/Extensions.cs b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/Extensions.cs index 6df89b2c63c2..8adc4263b7db 100644 --- a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/Extensions.cs +++ b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/NullableAttribute.cs b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/NullableAttribute.cs index 193e07f6958f..174c7003ba13 100644 --- a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedRequestParameters.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedRequestParameters.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/Optional.cs b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/Optional.cs index 638fd6cbba3e..6b3a5c0309e3 100644 --- a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/Optional.cs +++ b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/OptionalAttribute.cs b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/OptionalAttribute.cs index 4d9f9c710e77..3f6edeccc24e 100644 --- a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedRequestParameters.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/QueryStringBuilder.cs b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/QueryStringBuilder.cs index 6ae8be6cfb7d..bfd4cc331cbb 100644 --- a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/SeedRequestParameters.csproj b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/SeedRequestParameters.csproj index 68afedbd898e..0208916e3f4e 100644 --- a/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/SeedRequestParameters.csproj +++ b/seed/csharp-sdk/request-parameters/no-custom-config/src/SeedRequestParameters/SeedRequestParameters.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/request-parameters/fern + https://github.com/request-parameters/fern + git true diff --git a/seed/csharp-sdk/request-parameters/with-defaults/README.md b/seed/csharp-sdk/request-parameters/with-defaults/README.md index 03282a310b98..54a7d9e94bdd 100644 --- a/seed/csharp-sdk/request-parameters/with-defaults/README.md +++ b/seed/csharp-sdk/request-parameters/with-defaults/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.CreateUsernameAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.CreateUsernameAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.CreateUsernameAsync(...); +var parsedData = await client.User.CreateUsernameAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/Extensions.cs b/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/Extensions.cs index 6df89b2c63c2..8adc4263b7db 100644 --- a/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/Extensions.cs +++ b/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/NullableAttribute.cs b/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/NullableAttribute.cs index 193e07f6958f..174c7003ba13 100644 --- a/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedRequestParameters.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedRequestParameters.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/Optional.cs b/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/Optional.cs index 638fd6cbba3e..6b3a5c0309e3 100644 --- a/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/Optional.cs +++ b/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/OptionalAttribute.cs b/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/OptionalAttribute.cs index 4d9f9c710e77..3f6edeccc24e 100644 --- a/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedRequestParameters.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/QueryStringBuilder.cs b/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/QueryStringBuilder.cs index 6ae8be6cfb7d..bfd4cc331cbb 100644 --- a/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/SeedRequestParameters.csproj b/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/SeedRequestParameters.csproj index 4abdf1e244f5..7c0e35f32a3e 100644 --- a/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/SeedRequestParameters.csproj +++ b/seed/csharp-sdk/request-parameters/with-defaults/src/SeedRequestParameters/SeedRequestParameters.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/request-parameters/fern + https://github.com/request-parameters/fern + git true diff --git a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/README.md b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/README.md index 6ca83f6a4b06..dce47a0ac453 100644 --- a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/README.md +++ b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -107,7 +110,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetFooAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -120,7 +123,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetFooAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -150,7 +153,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetFooAsync(...); +var parsedData = await client.GetFooAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/SeedApi.csproj index 70c7583e1873..830838fe556f 100644 --- a/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/required-nullable/explicit-nullable-optional/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/required-nullable/fern + https://github.com/required-nullable/fern + git true diff --git a/seed/csharp-sdk/required-nullable/no-custom-config/README.md b/seed/csharp-sdk/required-nullable/no-custom-config/README.md index 6ca83f6a4b06..dce47a0ac453 100644 --- a/seed/csharp-sdk/required-nullable/no-custom-config/README.md +++ b/seed/csharp-sdk/required-nullable/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -107,7 +110,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetFooAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -120,7 +123,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetFooAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -150,7 +153,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetFooAsync(...); +var parsedData = await client.GetFooAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/SeedApi.csproj index 70c7583e1873..830838fe556f 100644 --- a/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/required-nullable/no-custom-config/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/required-nullable/fern + https://github.com/required-nullable/fern + git true diff --git a/seed/csharp-sdk/reserved-keywords/README.md b/seed/csharp-sdk/reserved-keywords/README.md index 90f91feb151a..290f65d1fe68 100644 --- a/seed/csharp-sdk/reserved-keywords/README.md +++ b/seed/csharp-sdk/reserved-keywords/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Package.TestAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Package.TestAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Package.TestAsync(...); +var parsedData = await client.Package.TestAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi.Test/Utils/OptionalComparer.cs index 34f69e450688..c563e27531e8 100644 --- a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/Extensions.cs b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/Extensions.cs index 19a63e5bc6dc..ab181fd0b8f1 100644 --- a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/Extensions.cs +++ b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/NullableAttribute.cs b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/NullableAttribute.cs index e3c3b3eea4b8..df8f95f706df 100644 --- a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedNurseryApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedNurseryApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/Optional.cs b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/Optional.cs index 5f655755302c..92f45c1a122a 100644 --- a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/Optional.cs +++ b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/OptionalAttribute.cs index 992233127ee3..2c9ed20e9074 100644 --- a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedNurseryApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/QueryStringBuilder.cs index 10ed4c343d10..d8101a543697 100644 --- a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/SeedNurseryApi.csproj b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/SeedNurseryApi.csproj index b78ab6153571..f31f297870fa 100644 --- a/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/SeedNurseryApi.csproj +++ b/seed/csharp-sdk/reserved-keywords/src/SeedNurseryApi/SeedNurseryApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/reserved-keywords/fern + https://github.com/reserved-keywords/fern + git true diff --git a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/README.md b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/README.md index dab5ffd8ec14..52858f13ce2f 100644 --- a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/README.md +++ b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -107,7 +110,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.RefundAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -120,7 +123,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.RefundAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -150,7 +153,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.RefundAsync(...); +var parsedData = await client.RefundAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/SeedApi.csproj index 18ec1881f289..13ec8cd58868 100644 --- a/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/respect-optional-request-body/no-custom-config/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/respect-optional-request-body/fern + https://github.com/respect-optional-request-body/fern + git true diff --git a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/README.md b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/README.md index dab5ffd8ec14..52858f13ce2f 100644 --- a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/README.md +++ b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -107,7 +110,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.RefundAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -120,7 +123,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.RefundAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -150,7 +153,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.RefundAsync(...); +var parsedData = await client.RefundAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/SeedApi.csproj index 18ec1881f289..13ec8cd58868 100644 --- a/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/respect-optional-request-body/respect-optional-request-body/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/respect-optional-request-body/fern + https://github.com/respect-optional-request-body/fern + git true diff --git a/seed/csharp-sdk/response-property/README.md b/seed/csharp-sdk/response-property/README.md index d87de42e753e..a16041dea6cd 100644 --- a/seed/csharp-sdk/response-property/README.md +++ b/seed/csharp-sdk/response-property/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.GetMovieAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.GetMovieAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.GetMovieAsync(...); +var parsedData = await client.Service.GetMovieAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/response-property/src/SeedResponseProperty.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/response-property/src/SeedResponseProperty.Test/Utils/OptionalComparer.cs index d2ee06293bf1..84f8b6313844 100644 --- a/seed/csharp-sdk/response-property/src/SeedResponseProperty.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/response-property/src/SeedResponseProperty.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/Extensions.cs b/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/Extensions.cs index a43723ef8523..dad6779d4c74 100644 --- a/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/Extensions.cs +++ b/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/NullableAttribute.cs b/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/NullableAttribute.cs index c566c0d947f6..8afac08e3959 100644 --- a/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedResponseProperty.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedResponseProperty.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/Optional.cs b/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/Optional.cs index 47d2188a79ca..d218e7412100 100644 --- a/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/Optional.cs +++ b/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/OptionalAttribute.cs b/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/OptionalAttribute.cs index 149d68bf37e8..5af76b6755b0 100644 --- a/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedResponseProperty.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/QueryStringBuilder.cs b/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/QueryStringBuilder.cs index 560aefa24f35..0b5ae179f342 100644 --- a/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/response-property/src/SeedResponseProperty/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/response-property/src/SeedResponseProperty/SeedResponseProperty.csproj b/seed/csharp-sdk/response-property/src/SeedResponseProperty/SeedResponseProperty.csproj index 7f21b2953983..bd6183d073eb 100644 --- a/seed/csharp-sdk/response-property/src/SeedResponseProperty/SeedResponseProperty.csproj +++ b/seed/csharp-sdk/response-property/src/SeedResponseProperty/SeedResponseProperty.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/response-property/fern + https://github.com/response-property/fern + git true diff --git a/seed/csharp-sdk/schemaless-request-body-examples/README.md b/seed/csharp-sdk/schemaless-request-body-examples/README.md index 84fc8cfaf1bc..747319ecd23c 100644 --- a/seed/csharp-sdk/schemaless-request-body-examples/README.md +++ b/seed/csharp-sdk/schemaless-request-body-examples/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -120,7 +123,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreatePlantAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -133,7 +136,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreatePlantAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -163,7 +166,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreatePlantAsync(...); +var parsedData = await client.CreatePlantAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/SeedApi.csproj index 6117871afb8a..b426d453d2ec 100644 --- a/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/schemaless-request-body-examples/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/schemaless-request-body-examples/fern + https://github.com/schemaless-request-body-examples/fern + git true diff --git a/seed/csharp-sdk/seed.yml b/seed/csharp-sdk/seed.yml index fe2a3df88fd1..65f9dced9710 100644 --- a/seed/csharp-sdk/seed.yml +++ b/seed/csharp-sdk/seed.yml @@ -420,6 +420,24 @@ fixtures: csharp-xml-entities: - customConfig: null outputFolder: no-custom-config + - customConfig: + package-metadata: + description: An SDK for the XML entities API. + authors: + - Fern + - Acme + tags: + - acme + - sdk + copyright: Copyright (c) Acme, Inc. + project-url: https://example.com/docs + repository-url: https://github.com/acme/acme-dotnet + include-source-link: true + include-symbols: true + outputFolder: package-metadata + - customConfig: + generate-documentation-file: false + outputFolder: no-documentation-file nullable: - customConfig: null outputFolder: no-custom-config diff --git a/seed/csharp-sdk/server-sent-event-examples/README.md b/seed/csharp-sdk/server-sent-event-examples/README.md index 55c20995b253..c88703801461 100644 --- a/seed/csharp-sdk/server-sent-event-examples/README.md +++ b/seed/csharp-sdk/server-sent-event-examples/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -106,7 +109,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Completions.StreamAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -119,7 +122,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Completions.StreamAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -149,7 +152,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Completions.StreamAsync(...); +var parsedData = await client.Completions.StreamAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents.Test/Utils/OptionalComparer.cs index b9d2a26d686d..99f0f40b7188 100644 --- a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/Extensions.cs b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/Extensions.cs index 7c344f25ff2e..d8fb69181d5c 100644 --- a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/Extensions.cs +++ b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/NullableAttribute.cs b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/NullableAttribute.cs index 8ece31e9fd41..12b3f0a1bc26 100644 --- a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedServerSentEvents.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedServerSentEvents.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/Optional.cs b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/Optional.cs index 203c54cd308e..d735cf219e12 100644 --- a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/Optional.cs +++ b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/OptionalAttribute.cs b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/OptionalAttribute.cs index e79983bfbf20..04bbf494cbf7 100644 --- a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedServerSentEvents.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/QueryStringBuilder.cs b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/QueryStringBuilder.cs index b807961a604a..45759458540b 100644 --- a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/SeedServerSentEvents.csproj b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/SeedServerSentEvents.csproj index 0df5589977f6..97894ef21a9b 100644 --- a/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/SeedServerSentEvents.csproj +++ b/seed/csharp-sdk/server-sent-event-examples/src/SeedServerSentEvents/SeedServerSentEvents.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/server-sent-event-examples/fern + https://github.com/server-sent-event-examples/fern + git true diff --git a/seed/csharp-sdk/server-sent-events-openapi/README.md b/seed/csharp-sdk/server-sent-events-openapi/README.md index 70c2052d48ba..1fbdaafcdb3c 100644 --- a/seed/csharp-sdk/server-sent-events-openapi/README.md +++ b/seed/csharp-sdk/server-sent-events-openapi/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -107,7 +110,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.StreamProtocolNoCollisionAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -120,7 +123,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.StreamProtocolNoCollisionAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -150,7 +153,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.StreamProtocolNoCollisionAsync(...); +var parsedData = await client.StreamProtocolNoCollisionAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/SeedApi.csproj index 78be859d8459..217b715e7f63 100644 --- a/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/server-sent-events-openapi/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/server-sent-events-openapi/fern + https://github.com/server-sent-events-openapi/fern + git true diff --git a/seed/csharp-sdk/server-sent-events-resumable/README.md b/seed/csharp-sdk/server-sent-events-resumable/README.md index bda067866824..715445746df0 100644 --- a/seed/csharp-sdk/server-sent-events-resumable/README.md +++ b/seed/csharp-sdk/server-sent-events-resumable/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -106,7 +109,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Completions.StreamAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -119,7 +122,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Completions.StreamAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -149,7 +152,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Completions.StreamAsync(...); +var parsedData = await client.Completions.StreamAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable.Test/Utils/OptionalComparer.cs index 4170c82e8f0c..673f6c121f67 100644 --- a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/Extensions.cs b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/Extensions.cs index d37f5e60f95f..d304dd2a5407 100644 --- a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/Extensions.cs +++ b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/NullableAttribute.cs b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/NullableAttribute.cs index 85792276fa5e..f64dd272a803 100644 --- a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedServerSentEventsResumable.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedServerSentEventsResumable.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/Optional.cs b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/Optional.cs index 5c953a2ccd23..abb920edeb77 100644 --- a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/Optional.cs +++ b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/OptionalAttribute.cs b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/OptionalAttribute.cs index 81bcc28392e8..8ac1a69e912b 100644 --- a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedServerSentEventsResumable.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/QueryStringBuilder.cs b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/QueryStringBuilder.cs index f4788bc5f708..49fcff017e42 100644 --- a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/SeedServerSentEventsResumable.csproj b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/SeedServerSentEventsResumable.csproj index 60aba5302843..b16a8971f8bd 100644 --- a/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/SeedServerSentEventsResumable.csproj +++ b/seed/csharp-sdk/server-sent-events-resumable/src/SeedServerSentEventsResumable/SeedServerSentEventsResumable.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/server-sent-events-resumable/fern + https://github.com/server-sent-events-resumable/fern + git true diff --git a/seed/csharp-sdk/server-sent-events/README.md b/seed/csharp-sdk/server-sent-events/README.md index a7426522557c..42ae8d94a9a8 100644 --- a/seed/csharp-sdk/server-sent-events/README.md +++ b/seed/csharp-sdk/server-sent-events/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -106,7 +109,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Completions.StreamAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -119,7 +122,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Completions.StreamAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -149,7 +152,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Completions.StreamAsync(...); +var parsedData = await client.Completions.StreamAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents.Test/Utils/OptionalComparer.cs index b9d2a26d686d..99f0f40b7188 100644 --- a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/Extensions.cs b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/Extensions.cs index 7c344f25ff2e..d8fb69181d5c 100644 --- a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/Extensions.cs +++ b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/NullableAttribute.cs b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/NullableAttribute.cs index 8ece31e9fd41..12b3f0a1bc26 100644 --- a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedServerSentEvents.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedServerSentEvents.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/Optional.cs b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/Optional.cs index 203c54cd308e..d735cf219e12 100644 --- a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/Optional.cs +++ b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/OptionalAttribute.cs b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/OptionalAttribute.cs index e79983bfbf20..04bbf494cbf7 100644 --- a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedServerSentEvents.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/QueryStringBuilder.cs b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/QueryStringBuilder.cs index b807961a604a..45759458540b 100644 --- a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/SeedServerSentEvents.csproj b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/SeedServerSentEvents.csproj index db71dad490a0..80082e56ad6a 100644 --- a/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/SeedServerSentEvents.csproj +++ b/seed/csharp-sdk/server-sent-events/src/SeedServerSentEvents/SeedServerSentEvents.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/server-sent-events/fern + https://github.com/server-sent-events/fern + git true diff --git a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/README.md b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/README.md index 171787df66a3..9ca8fce77985 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/README.md +++ b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetUsersAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetUsersAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetUsersAsync(...); +var parsedData = await client.GetUsersAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/SeedApi.csproj index 644b88b041aa..efba15153188 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/server-url-templating-single-url/disable-server-url-variables/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/server-url-templating-single-url/fern + https://github.com/server-url-templating-single-url/fern + git true diff --git a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/README.md b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/README.md index 171787df66a3..9ca8fce77985 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/README.md +++ b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetUsersAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetUsersAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetUsersAsync(...); +var parsedData = await client.GetUsersAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/SeedApi.csproj index 644b88b041aa..efba15153188 100644 --- a/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/server-url-templating-single-url/no-custom-config/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/server-url-templating-single-url/fern + https://github.com/server-url-templating-single-url/fern + git true diff --git a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/README.md b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/README.md index 02e2ca4936c5..9533aaec148d 100644 --- a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/README.md +++ b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -117,7 +120,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -130,7 +133,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -160,7 +163,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetTokenAsync(...); +var parsedData = await client.GetTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/SeedApi.csproj index f1b84cfe7a3f..753071cc44c4 100644 --- a/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/server-url-templating/disable-server-url-variables/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/server-url-templating/fern + https://github.com/server-url-templating/fern + git true diff --git a/seed/csharp-sdk/server-url-templating/no-custom-config/README.md b/seed/csharp-sdk/server-url-templating/no-custom-config/README.md index 02e2ca4936c5..9533aaec148d 100644 --- a/seed/csharp-sdk/server-url-templating/no-custom-config/README.md +++ b/seed/csharp-sdk/server-url-templating/no-custom-config/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -117,7 +120,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetTokenAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -130,7 +133,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetTokenAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -160,7 +163,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetTokenAsync(...); +var parsedData = await client.GetTokenAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/SeedApi.csproj index f1b84cfe7a3f..753071cc44c4 100644 --- a/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/server-url-templating/no-custom-config/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/server-url-templating/fern + https://github.com/server-url-templating/fern + git true diff --git a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/README.md b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/README.md index 271377e68132..e83acbddf109 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/README.md +++ b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.GetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.GetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.GetAsync(...); +var parsedData = await client.User.GetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/Extensions.cs b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/Extensions.cs index a0dd0f7595ef..b7dc53199d6c 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/Extensions.cs +++ b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/NullableAttribute.cs b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/NullableAttribute.cs index cb2a8aafd8f8..213cc239a748 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedSimpleApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedSimpleApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/Optional.cs b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/Optional.cs index 3e2a2a8a0565..e4bfd33a94ef 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/Optional.cs +++ b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/OptionalAttribute.cs index 08d8072360ef..16e495db5460 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedSimpleApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/QueryStringBuilder.cs index 79c91f9fe908..d25efcbe6cde 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/SeedSimpleApi.csproj b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/SeedSimpleApi.csproj index fff1a13d6a94..9d05dc3ab3a1 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/SeedSimpleApi.csproj +++ b/seed/csharp-sdk/simple-api/custom-output-path-object/lib/SeedApi/SeedSimpleApi/SeedSimpleApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/simple-api/fern + https://github.com/simple-api/fern + git true diff --git a/seed/csharp-sdk/simple-api/custom-output-path-object/test/SeedApi.Test/SeedSimpleApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/simple-api/custom-output-path-object/test/SeedApi.Test/SeedSimpleApi.Test/Utils/OptionalComparer.cs index 139a54732317..705dd1c23275 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path-object/test/SeedApi.Test/SeedSimpleApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/simple-api/custom-output-path-object/test/SeedApi.Test/SeedSimpleApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/simple-api/custom-output-path/README.md b/seed/csharp-sdk/simple-api/custom-output-path/README.md index 271377e68132..e83acbddf109 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path/README.md +++ b/seed/csharp-sdk/simple-api/custom-output-path/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.GetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.GetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.GetAsync(...); +var parsedData = await client.User.GetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi.Test/Utils/OptionalComparer.cs index 139a54732317..705dd1c23275 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/Extensions.cs b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/Extensions.cs index a0dd0f7595ef..b7dc53199d6c 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/Extensions.cs +++ b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/NullableAttribute.cs b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/NullableAttribute.cs index cb2a8aafd8f8..213cc239a748 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedSimpleApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedSimpleApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/Optional.cs b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/Optional.cs index 3e2a2a8a0565..e4bfd33a94ef 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/Optional.cs +++ b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/OptionalAttribute.cs index 08d8072360ef..16e495db5460 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedSimpleApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/QueryStringBuilder.cs index 79c91f9fe908..d25efcbe6cde 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/SeedSimpleApi.csproj b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/SeedSimpleApi.csproj index d62d86b73ca4..6c79933012d0 100644 --- a/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/SeedSimpleApi.csproj +++ b/seed/csharp-sdk/simple-api/custom-output-path/custom-src/SeedSimpleApi/SeedSimpleApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/simple-api/fern + https://github.com/simple-api/fern + git true diff --git a/seed/csharp-sdk/simple-api/no-custom-config/README.md b/seed/csharp-sdk/simple-api/no-custom-config/README.md index 271377e68132..e83acbddf109 100644 --- a/seed/csharp-sdk/simple-api/no-custom-config/README.md +++ b/seed/csharp-sdk/simple-api/no-custom-config/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.GetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.GetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.GetAsync(...); +var parsedData = await client.User.GetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi.Test/Utils/OptionalComparer.cs index 139a54732317..705dd1c23275 100644 --- a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/Extensions.cs b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/Extensions.cs index a0dd0f7595ef..b7dc53199d6c 100644 --- a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/Extensions.cs +++ b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/NullableAttribute.cs b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/NullableAttribute.cs index cb2a8aafd8f8..213cc239a748 100644 --- a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedSimpleApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedSimpleApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/Optional.cs b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/Optional.cs index 3e2a2a8a0565..e4bfd33a94ef 100644 --- a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/Optional.cs +++ b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/OptionalAttribute.cs index 08d8072360ef..16e495db5460 100644 --- a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedSimpleApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/QueryStringBuilder.cs index 79c91f9fe908..d25efcbe6cde 100644 --- a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/SeedSimpleApi.csproj b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/SeedSimpleApi.csproj index d62d86b73ca4..6c79933012d0 100644 --- a/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/SeedSimpleApi.csproj +++ b/seed/csharp-sdk/simple-api/no-custom-config/src/SeedSimpleApi/SeedSimpleApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/simple-api/fern + https://github.com/simple-api/fern + git true diff --git a/seed/csharp-sdk/simple-api/use-sln-format/README.md b/seed/csharp-sdk/simple-api/use-sln-format/README.md index 271377e68132..e83acbddf109 100644 --- a/seed/csharp-sdk/simple-api/use-sln-format/README.md +++ b/seed/csharp-sdk/simple-api/use-sln-format/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.GetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.GetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.GetAsync(...); +var parsedData = await client.User.GetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi.Test/Utils/OptionalComparer.cs index 139a54732317..705dd1c23275 100644 --- a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/Extensions.cs b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/Extensions.cs index a0dd0f7595ef..b7dc53199d6c 100644 --- a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/Extensions.cs +++ b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/NullableAttribute.cs b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/NullableAttribute.cs index cb2a8aafd8f8..213cc239a748 100644 --- a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedSimpleApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedSimpleApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/Optional.cs b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/Optional.cs index 3e2a2a8a0565..e4bfd33a94ef 100644 --- a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/Optional.cs +++ b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/OptionalAttribute.cs index 08d8072360ef..16e495db5460 100644 --- a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedSimpleApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/QueryStringBuilder.cs index 79c91f9fe908..d25efcbe6cde 100644 --- a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/SeedSimpleApi.csproj b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/SeedSimpleApi.csproj index d62d86b73ca4..6c79933012d0 100644 --- a/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/SeedSimpleApi.csproj +++ b/seed/csharp-sdk/simple-api/use-sln-format/src/SeedSimpleApi/SeedSimpleApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/simple-api/fern + https://github.com/simple-api/fern + git true diff --git a/seed/csharp-sdk/simple-fhir/README.md b/seed/csharp-sdk/simple-fhir/README.md index 1be4fee450da..17e550a062f2 100644 --- a/seed/csharp-sdk/simple-fhir/README.md +++ b/seed/csharp-sdk/simple-fhir/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetAccountAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetAccountAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetAccountAsync(...); +var parsedData = await client.GetAccountAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/simple-fhir/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/simple-fhir/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/simple-fhir/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/simple-fhir/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/simple-fhir/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/simple-fhir/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/simple-fhir/src/SeedApi/SeedApi.csproj index 88549120062e..9d1fcbad575d 100644 --- a/seed/csharp-sdk/simple-fhir/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/simple-fhir/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/simple-fhir/fern + https://github.com/simple-fhir/fern + git true diff --git a/seed/csharp-sdk/single-url-environment-default/README.md b/seed/csharp-sdk/single-url-environment-default/README.md index 94ff47021b38..e05f6b464e90 100644 --- a/seed/csharp-sdk/single-url-environment-default/README.md +++ b/seed/csharp-sdk/single-url-environment-default/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Dummy.GetDummyAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Dummy.GetDummyAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Dummy.GetDummyAsync(...); +var parsedData = await client.Dummy.GetDummyAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault.Test/Utils/OptionalComparer.cs index 1af4b45feb17..dbb90cd40792 100644 --- a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/Extensions.cs b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/Extensions.cs index c13e84355ac4..c8c199b29aad 100644 --- a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/Extensions.cs +++ b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/NullableAttribute.cs b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/NullableAttribute.cs index 0f7a3a2a3add..93e649239a2d 100644 --- a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedSingleUrlEnvironmentDefault.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedSingleUrlEnvironmentDefault.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/Optional.cs b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/Optional.cs index f0f823597c32..587f66d915e7 100644 --- a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/Optional.cs +++ b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/OptionalAttribute.cs b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/OptionalAttribute.cs index f1ba2cc29f35..a61dee9eb967 100644 --- a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedSingleUrlEnvironmentDefault.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/QueryStringBuilder.cs b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/QueryStringBuilder.cs index 52db7fb57a9a..899e7a0fc187 100644 --- a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/SeedSingleUrlEnvironmentDefault.csproj b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/SeedSingleUrlEnvironmentDefault.csproj index 1ee68d8ef7e5..c70b38df975d 100644 --- a/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/SeedSingleUrlEnvironmentDefault.csproj +++ b/seed/csharp-sdk/single-url-environment-default/src/SeedSingleUrlEnvironmentDefault/SeedSingleUrlEnvironmentDefault.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/single-url-environment-default/fern + https://github.com/single-url-environment-default/fern + git true diff --git a/seed/csharp-sdk/single-url-environment-no-default/README.md b/seed/csharp-sdk/single-url-environment-no-default/README.md index f3e01283758c..bdaaf9ee8d3d 100644 --- a/seed/csharp-sdk/single-url-environment-no-default/README.md +++ b/seed/csharp-sdk/single-url-environment-no-default/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Dummy.GetDummyAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Dummy.GetDummyAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Dummy.GetDummyAsync(...); +var parsedData = await client.Dummy.GetDummyAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault.Test/Utils/OptionalComparer.cs index 0a26b858622f..39a861c34cb4 100644 --- a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/Extensions.cs b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/Extensions.cs index fc37213ee73e..b69abad360f1 100644 --- a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/Extensions.cs +++ b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/NullableAttribute.cs b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/NullableAttribute.cs index 4fdd853aac00..0d59c52d2c10 100644 --- a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedSingleUrlEnvironmentNoDefault.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedSingleUrlEnvironmentNoDefault.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/Optional.cs b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/Optional.cs index 7312d30ac9a3..939a9e34119c 100644 --- a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/Optional.cs +++ b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/OptionalAttribute.cs b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/OptionalAttribute.cs index 29dcbff60cd8..877a9403eee6 100644 --- a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedSingleUrlEnvironmentNoDefault.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/QueryStringBuilder.cs b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/QueryStringBuilder.cs index b2eef93623a1..e95f90a5c665 100644 --- a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/SeedSingleUrlEnvironmentNoDefault.csproj b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/SeedSingleUrlEnvironmentNoDefault.csproj index 4c78a3802d04..96f94f6ccba9 100644 --- a/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/SeedSingleUrlEnvironmentNoDefault.csproj +++ b/seed/csharp-sdk/single-url-environment-no-default/src/SeedSingleUrlEnvironmentNoDefault/SeedSingleUrlEnvironmentNoDefault.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/single-url-environment-no-default/fern + https://github.com/single-url-environment-no-default/fern + git true diff --git a/seed/csharp-sdk/streaming-parameter/README.md b/seed/csharp-sdk/streaming-parameter/README.md index 597adb79dd85..04e9db46f485 100644 --- a/seed/csharp-sdk/streaming-parameter/README.md +++ b/seed/csharp-sdk/streaming-parameter/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -106,7 +109,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Dummy.GenerateAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -119,7 +122,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Dummy.GenerateAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -149,7 +152,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Dummy.GenerateAsync(...); +var parsedData = await client.Dummy.GenerateAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming.Test/Utils/OptionalComparer.cs index ea0fb2cb6865..e1cdfa5ec4a2 100644 --- a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/Extensions.cs b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/Extensions.cs index 2fb3103f35af..a79b17e6bf39 100644 --- a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/Extensions.cs +++ b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/NullableAttribute.cs b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/NullableAttribute.cs index 77ea9e22958d..8e9285fb1676 100644 --- a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedStreaming.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedStreaming.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/Optional.cs b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/Optional.cs index 239fff2f28cd..775fba9ba739 100644 --- a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/Optional.cs +++ b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/OptionalAttribute.cs b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/OptionalAttribute.cs index 5f450986a9eb..a869a3fff8ed 100644 --- a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedStreaming.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/QueryStringBuilder.cs b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/QueryStringBuilder.cs index f5bd9fe6b08d..020a19027c31 100644 --- a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/SeedStreaming.csproj b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/SeedStreaming.csproj index b02bddfc4ed3..bda8d36a6132 100644 --- a/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/SeedStreaming.csproj +++ b/seed/csharp-sdk/streaming-parameter/src/SeedStreaming/SeedStreaming.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/streaming-parameter/fern + https://github.com/streaming-parameter/fern + git true diff --git a/seed/csharp-sdk/streaming/no-custom-config/README.md b/seed/csharp-sdk/streaming/no-custom-config/README.md index 1c4e43d9ca18..201e66fd89db 100644 --- a/seed/csharp-sdk/streaming/no-custom-config/README.md +++ b/seed/csharp-sdk/streaming/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -106,7 +109,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Dummy.GenerateStreamAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -119,7 +122,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Dummy.GenerateStreamAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -149,7 +152,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Dummy.GenerateStreamAsync(...); +var parsedData = await client.Dummy.GenerateStreamAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming.Test/Utils/OptionalComparer.cs index ea0fb2cb6865..e1cdfa5ec4a2 100644 --- a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/Extensions.cs b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/Extensions.cs index 2fb3103f35af..a79b17e6bf39 100644 --- a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/Extensions.cs +++ b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/NullableAttribute.cs b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/NullableAttribute.cs index 77ea9e22958d..8e9285fb1676 100644 --- a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedStreaming.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedStreaming.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/Optional.cs b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/Optional.cs index 239fff2f28cd..775fba9ba739 100644 --- a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/Optional.cs +++ b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/OptionalAttribute.cs b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/OptionalAttribute.cs index 5f450986a9eb..a869a3fff8ed 100644 --- a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedStreaming.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/QueryStringBuilder.cs b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/QueryStringBuilder.cs index f5bd9fe6b08d..020a19027c31 100644 --- a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/SeedStreaming.csproj b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/SeedStreaming.csproj index 61c13175df8f..66a3275111cd 100644 --- a/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/SeedStreaming.csproj +++ b/seed/csharp-sdk/streaming/no-custom-config/src/SeedStreaming/SeedStreaming.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/streaming/fern + https://github.com/streaming/fern + git true diff --git a/seed/csharp-sdk/streaming/redact-response-body-on-error/README.md b/seed/csharp-sdk/streaming/redact-response-body-on-error/README.md index 1c4e43d9ca18..201e66fd89db 100644 --- a/seed/csharp-sdk/streaming/redact-response-body-on-error/README.md +++ b/seed/csharp-sdk/streaming/redact-response-body-on-error/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -106,7 +109,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Dummy.GenerateStreamAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -119,7 +122,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Dummy.GenerateStreamAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -149,7 +152,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Dummy.GenerateStreamAsync(...); +var parsedData = await client.Dummy.GenerateStreamAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming.Test/Utils/OptionalComparer.cs index ea0fb2cb6865..e1cdfa5ec4a2 100644 --- a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/Extensions.cs b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/Extensions.cs index 2fb3103f35af..a79b17e6bf39 100644 --- a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/Extensions.cs +++ b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/NullableAttribute.cs b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/NullableAttribute.cs index 77ea9e22958d..8e9285fb1676 100644 --- a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedStreaming.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedStreaming.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/Optional.cs b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/Optional.cs index 239fff2f28cd..775fba9ba739 100644 --- a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/Optional.cs +++ b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/OptionalAttribute.cs b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/OptionalAttribute.cs index 5f450986a9eb..a869a3fff8ed 100644 --- a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedStreaming.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/QueryStringBuilder.cs b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/QueryStringBuilder.cs index f5bd9fe6b08d..020a19027c31 100644 --- a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/SeedStreaming.csproj b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/SeedStreaming.csproj index 61c13175df8f..66a3275111cd 100644 --- a/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/SeedStreaming.csproj +++ b/seed/csharp-sdk/streaming/redact-response-body-on-error/src/SeedStreaming/SeedStreaming.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/streaming/fern + https://github.com/streaming/fern + git true diff --git a/seed/csharp-sdk/trace/README.md b/seed/csharp-sdk/trace/README.md index 38f2f0b01d11..d05252efea59 100644 --- a/seed/csharp-sdk/trace/README.md +++ b/seed/csharp-sdk/trace/README.md @@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -119,7 +122,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Admin.UpdateTestSubmissionStatusAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -132,7 +135,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Admin.UpdateTestSubmissionStatusAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -162,7 +165,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Admin.UpdateTestSubmissionStatusAsync(...); +var parsedData = await client.Admin.UpdateTestSubmissionStatusAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/trace/src/SeedTrace.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/trace/src/SeedTrace.Test/Utils/OptionalComparer.cs index 537dd577bc00..b01508078420 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Commons/Types/DebugVariableValue.cs b/seed/csharp-sdk/trace/src/SeedTrace/Commons/Types/DebugVariableValue.cs index a53e557a4110..3d854c3d802a 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Commons/Types/DebugVariableValue.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Commons/Types/DebugVariableValue.cs @@ -266,7 +266,7 @@ public SeedTrace.DebugMapValue AsMapValue() => : throw new global::System.Exception("DebugVariableValue.Type is not 'mapValue'"); /// - /// Returns the value as a if is 'listValue', otherwise throws an exception. + /// Returns the value as a if is 'listValue', otherwise throws an exception. /// /// Thrown when is not 'listValue'. public IEnumerable AsListValue() => @@ -308,7 +308,7 @@ public SeedTrace.DoublyLinkedListNodeAndListValue AsDoublyLinkedListNodeValue() ); /// - /// Returns the value as a if is 'undefinedValue', otherwise throws an exception. + /// Returns the value as a if is 'undefinedValue', otherwise throws an exception. /// /// Thrown when is not 'undefinedValue'. public object? AsUndefinedValue() => @@ -317,7 +317,7 @@ public SeedTrace.DoublyLinkedListNodeAndListValue AsDoublyLinkedListNodeValue() : throw new global::System.Exception("DebugVariableValue.Type is not 'undefinedValue'"); /// - /// Returns the value as a if is 'nullValue', otherwise throws an exception. + /// Returns the value as a if is 'nullValue', otherwise throws an exception. /// /// Thrown when is not 'nullValue'. public object? AsNullValue() => @@ -523,7 +523,7 @@ public bool TryAsMapValue(out SeedTrace.DebugMapValue? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsListValue(out IEnumerable? value) { @@ -583,7 +583,7 @@ out SeedTrace.DoublyLinkedListNodeAndListValue? value } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsUndefinedValue(out object? value) { @@ -597,7 +597,7 @@ public bool TryAsUndefinedValue(out object? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsNullValue(out object? value) { diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Commons/Types/VariableType.cs b/seed/csharp-sdk/trace/src/SeedTrace/Commons/Types/VariableType.cs index e06f6b0f2b3e..c69ff270ed7d 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Commons/Types/VariableType.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Commons/Types/VariableType.cs @@ -170,7 +170,7 @@ public VariableType(VariableType.DoublyLinkedListType value) public bool IsDoublyLinkedListType => Type == "doublyLinkedListType"; /// - /// Returns the value as a if is 'integerType', otherwise throws an exception. + /// Returns the value as a if is 'integerType', otherwise throws an exception. /// /// Thrown when is not 'integerType'. public object? AsIntegerType() => @@ -179,7 +179,7 @@ public VariableType(VariableType.DoublyLinkedListType value) : throw new global::System.Exception("VariableType.Type is not 'integerType'"); /// - /// Returns the value as a if is 'doubleType', otherwise throws an exception. + /// Returns the value as a if is 'doubleType', otherwise throws an exception. /// /// Thrown when is not 'doubleType'. public object? AsDoubleType() => @@ -188,7 +188,7 @@ public VariableType(VariableType.DoublyLinkedListType value) : throw new global::System.Exception("VariableType.Type is not 'doubleType'"); /// - /// Returns the value as a if is 'booleanType', otherwise throws an exception. + /// Returns the value as a if is 'booleanType', otherwise throws an exception. /// /// Thrown when is not 'booleanType'. public object? AsBooleanType() => @@ -197,7 +197,7 @@ public VariableType(VariableType.DoublyLinkedListType value) : throw new global::System.Exception("VariableType.Type is not 'booleanType'"); /// - /// Returns the value as a if is 'stringType', otherwise throws an exception. + /// Returns the value as a if is 'stringType', otherwise throws an exception. /// /// Thrown when is not 'stringType'. public object? AsStringType() => @@ -206,7 +206,7 @@ public VariableType(VariableType.DoublyLinkedListType value) : throw new global::System.Exception("VariableType.Type is not 'stringType'"); /// - /// Returns the value as a if is 'charType', otherwise throws an exception. + /// Returns the value as a if is 'charType', otherwise throws an exception. /// /// Thrown when is not 'charType'. public object? AsCharType() => @@ -233,7 +233,7 @@ public SeedTrace.MapType AsMapType() => : throw new global::System.Exception("VariableType.Type is not 'mapType'"); /// - /// Returns the value as a if is 'binaryTreeType', otherwise throws an exception. + /// Returns the value as a if is 'binaryTreeType', otherwise throws an exception. /// /// Thrown when is not 'binaryTreeType'. public object? AsBinaryTreeType() => @@ -242,7 +242,7 @@ public SeedTrace.MapType AsMapType() => : throw new global::System.Exception("VariableType.Type is not 'binaryTreeType'"); /// - /// Returns the value as a if is 'singlyLinkedListType', otherwise throws an exception. + /// Returns the value as a if is 'singlyLinkedListType', otherwise throws an exception. /// /// Thrown when is not 'singlyLinkedListType'. public object? AsSinglyLinkedListType() => @@ -251,7 +251,7 @@ public SeedTrace.MapType AsMapType() => : throw new global::System.Exception("VariableType.Type is not 'singlyLinkedListType'"); /// - /// Returns the value as a if is 'doublyLinkedListType', otherwise throws an exception. + /// Returns the value as a if is 'doublyLinkedListType', otherwise throws an exception. /// /// Thrown when is not 'doublyLinkedListType'. public object? AsDoublyLinkedListType() => @@ -342,7 +342,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsIntegerType(out object? value) { @@ -356,7 +356,7 @@ public bool TryAsIntegerType(out object? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsDoubleType(out object? value) { @@ -370,7 +370,7 @@ public bool TryAsDoubleType(out object? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsBooleanType(out object? value) { @@ -384,7 +384,7 @@ public bool TryAsBooleanType(out object? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsStringType(out object? value) { @@ -398,7 +398,7 @@ public bool TryAsStringType(out object? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsCharType(out object? value) { @@ -440,7 +440,7 @@ public bool TryAsMapType(out SeedTrace.MapType? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsBinaryTreeType(out object? value) { @@ -454,7 +454,7 @@ public bool TryAsBinaryTreeType(out object? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsSinglyLinkedListType(out object? value) { @@ -468,7 +468,7 @@ public bool TryAsSinglyLinkedListType(out object? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsDoublyLinkedListType(out object? value) { diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Commons/Types/VariableValue.cs b/seed/csharp-sdk/trace/src/SeedTrace/Commons/Types/VariableValue.cs index 9c98e18dd67d..3913cda04e62 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Commons/Types/VariableValue.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Commons/Types/VariableValue.cs @@ -238,7 +238,7 @@ public SeedTrace.MapValue AsMapValue() => : throw new global::System.Exception("VariableValue.Type is not 'mapValue'"); /// - /// Returns the value as a if is 'listValue', otherwise throws an exception. + /// Returns the value as a if is 'listValue', otherwise throws an exception. /// /// Thrown when is not 'listValue'. public IEnumerable AsListValue() => @@ -278,7 +278,7 @@ public SeedTrace.DoublyLinkedListValue AsDoublyLinkedListValue() => ); /// - /// Returns the value as a if is 'nullValue', otherwise throws an exception. + /// Returns the value as a if is 'nullValue', otherwise throws an exception. /// /// Thrown when is not 'nullValue'. public object? AsNullValue() => @@ -459,7 +459,7 @@ public bool TryAsMapValue(out SeedTrace.MapValue? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsListValue(out IEnumerable? value) { @@ -515,7 +515,7 @@ public bool TryAsDoublyLinkedListValue(out SeedTrace.DoublyLinkedListValue? valu } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsNullValue(out object? value) { diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Core/Extensions.cs b/seed/csharp-sdk/trace/src/SeedTrace/Core/Extensions.cs index 3bd48f3a5393..1763824d8a0a 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Core/Extensions.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Core/NullableAttribute.cs b/seed/csharp-sdk/trace/src/SeedTrace/Core/NullableAttribute.cs index 8e60015a7dce..2ca15d74a5a4 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedTrace.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedTrace.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Core/Optional.cs b/seed/csharp-sdk/trace/src/SeedTrace/Core/Optional.cs index 1d5c3d5420ed..85571b731085 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Core/Optional.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Core/OptionalAttribute.cs b/seed/csharp-sdk/trace/src/SeedTrace/Core/OptionalAttribute.cs index 07465625222f..d59dc4237cc3 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedTrace.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Core/QueryStringBuilder.cs b/seed/csharp-sdk/trace/src/SeedTrace/Core/QueryStringBuilder.cs index b42c742a8035..b01d90452229 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/trace/src/SeedTrace/SeedTrace.csproj b/seed/csharp-sdk/trace/src/SeedTrace/SeedTrace.csproj index 1aaf736b5523..2ed0f263e12b 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/SeedTrace.csproj +++ b/seed/csharp-sdk/trace/src/SeedTrace/SeedTrace.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/trace/fern + https://github.com/trace/fern + git true diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/ExceptionV2.cs b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/ExceptionV2.cs index a75b87d84cee..899a07ffc79b 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/ExceptionV2.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/ExceptionV2.cs @@ -67,7 +67,7 @@ public SeedTrace.ExceptionInfo AsGeneric() => : throw new global::System.Exception("ExceptionV2.Type is not 'generic'"); /// - /// Returns the value as a if is 'timeout', otherwise throws an exception. + /// Returns the value as a if is 'timeout', otherwise throws an exception. /// /// Thrown when is not 'timeout'. public object? AsTimeout() => @@ -124,7 +124,7 @@ public bool TryAsGeneric(out SeedTrace.ExceptionInfo? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsTimeout(out object? value) { diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/SubmissionRequest.cs b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/SubmissionRequest.cs index 181124aebce3..c9e79bddd804 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/SubmissionRequest.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/SubmissionRequest.cs @@ -111,7 +111,7 @@ public SeedTrace.InitializeProblemRequest AsInitializeProblemRequest() => ); /// - /// Returns the value as a if is 'initializeWorkspaceRequest', otherwise throws an exception. + /// Returns the value as a if is 'initializeWorkspaceRequest', otherwise throws an exception. /// /// Thrown when is not 'initializeWorkspaceRequest'. public object? AsInitializeWorkspaceRequest() => @@ -217,7 +217,7 @@ public bool TryAsInitializeProblemRequest(out SeedTrace.InitializeProblemRequest } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsInitializeWorkspaceRequest(out object? value) { diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/SubmissionResponse.cs b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/SubmissionResponse.cs index 1ba6d9fb8061..8ba89e646a58 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/SubmissionResponse.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/SubmissionResponse.cs @@ -114,7 +114,7 @@ public SubmissionResponse(SubmissionResponse.Terminated value) public bool IsTerminated => Type == "terminated"; /// - /// Returns the value as a if is 'serverInitialized', otherwise throws an exception. + /// Returns the value as a if is 'serverInitialized', otherwise throws an exception. /// /// Thrown when is not 'serverInitialized'. public object? AsServerInitialized() => @@ -136,7 +136,7 @@ public string AsProblemInitialized() => ); /// - /// Returns the value as a if is 'workspaceInitialized', otherwise throws an exception. + /// Returns the value as a if is 'workspaceInitialized', otherwise throws an exception. /// /// Thrown when is not 'workspaceInitialized'. public object? AsWorkspaceInitialized() => @@ -234,7 +234,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsServerInitialized(out object? value) { @@ -262,7 +262,7 @@ public bool TryAsProblemInitialized(out string? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsWorkspaceInitialized(out object? value) { diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/TestSubmissionStatus.cs b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/TestSubmissionStatus.cs index e9c51adc1f1e..65c581fbae5d 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/TestSubmissionStatus.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/TestSubmissionStatus.cs @@ -86,7 +86,7 @@ public TestSubmissionStatus(TestSubmissionStatus.TestCaseIdToState value) public bool IsTestCaseIdToState => Type == "testCaseIdToState"; /// - /// Returns the value as a if is 'stopped', otherwise throws an exception. + /// Returns the value as a if is 'stopped', otherwise throws an exception. /// /// Thrown when is not 'stopped'. public object? AsStopped() => @@ -113,7 +113,7 @@ public SeedTrace.RunningSubmissionState AsRunning() => : throw new global::System.Exception("TestSubmissionStatus.Type is not 'running'"); /// - /// Returns the value as a if is 'testCaseIdToState', otherwise throws an exception. + /// Returns the value as a if is 'testCaseIdToState', otherwise throws an exception. /// /// Thrown when is not 'testCaseIdToState'. public Dictionary AsTestCaseIdToState() => @@ -170,7 +170,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsStopped(out object? value) { @@ -212,7 +212,7 @@ public bool TryAsRunning(out SeedTrace.RunningSubmissionState? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsTestCaseIdToState(out Dictionary? value) { diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/TestSubmissionUpdateInfo.cs b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/TestSubmissionUpdateInfo.cs index 4fdf73643097..c406af03ffe6 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/TestSubmissionUpdateInfo.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/TestSubmissionUpdateInfo.cs @@ -123,7 +123,7 @@ public SeedTrace.RunningSubmissionState AsRunning() => : throw new global::System.Exception("TestSubmissionUpdateInfo.Type is not 'running'"); /// - /// Returns the value as a if is 'stopped', otherwise throws an exception. + /// Returns the value as a if is 'stopped', otherwise throws an exception. /// /// Thrown when is not 'stopped'. public object? AsStopped() => @@ -163,7 +163,7 @@ public SeedTrace.RecordedTestCaseUpdate AsRecordedTestCase() => ); /// - /// Returns the value as a if is 'finished', otherwise throws an exception. + /// Returns the value as a if is 'finished', otherwise throws an exception. /// /// Thrown when is not 'finished'. public object? AsFinished() => @@ -244,7 +244,7 @@ public bool TryAsRunning(out SeedTrace.RunningSubmissionState? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsStopped(out object? value) { @@ -300,7 +300,7 @@ public bool TryAsRecordedTestCase(out SeedTrace.RecordedTestCaseUpdate? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsFinished(out object? value) { diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/WorkspaceSubmissionStatus.cs b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/WorkspaceSubmissionStatus.cs index f1cdc430795c..23751cce350b 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/WorkspaceSubmissionStatus.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/WorkspaceSubmissionStatus.cs @@ -100,7 +100,7 @@ public WorkspaceSubmissionStatus(WorkspaceSubmissionStatus.Traced value) public bool IsTraced => Type == "traced"; /// - /// Returns the value as a if is 'stopped', otherwise throws an exception. + /// Returns the value as a if is 'stopped', otherwise throws an exception. /// /// Thrown when is not 'stopped'. public object? AsStopped() => @@ -197,7 +197,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsStopped(out object? value) { diff --git a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/WorkspaceSubmissionUpdateInfo.cs b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/WorkspaceSubmissionUpdateInfo.cs index f776cce7bcb6..938f8658c55a 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/WorkspaceSubmissionUpdateInfo.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/Submission/Types/WorkspaceSubmissionUpdateInfo.cs @@ -148,7 +148,7 @@ public SeedTrace.WorkspaceRunDetails AsRan() => : throw new global::System.Exception("WorkspaceSubmissionUpdateInfo.Type is not 'ran'"); /// - /// Returns the value as a if is 'stopped', otherwise throws an exception. + /// Returns the value as a if is 'stopped', otherwise throws an exception. /// /// Thrown when is not 'stopped'. public object? AsStopped() => @@ -159,7 +159,7 @@ public SeedTrace.WorkspaceRunDetails AsRan() => ); /// - /// Returns the value as a if is 'traced', otherwise throws an exception. + /// Returns the value as a if is 'traced', otherwise throws an exception. /// /// Thrown when is not 'traced'. public object? AsTraced() => @@ -192,7 +192,7 @@ public SeedTrace.ErrorInfo AsErrored() => ); /// - /// Returns the value as a if is 'finished', otherwise throws an exception. + /// Returns the value as a if is 'finished', otherwise throws an exception. /// /// Thrown when is not 'finished'. public object? AsFinished() => @@ -295,7 +295,7 @@ public bool TryAsRan(out SeedTrace.WorkspaceRunDetails? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsStopped(out object? value) { @@ -309,7 +309,7 @@ public bool TryAsStopped(out object? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsTraced(out object? value) { @@ -351,7 +351,7 @@ public bool TryAsErrored(out SeedTrace.ErrorInfo? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsFinished(out object? value) { diff --git a/seed/csharp-sdk/trace/src/SeedTrace/V2/Problem/Types/CustomFiles.cs b/seed/csharp-sdk/trace/src/SeedTrace/V2/Problem/Types/CustomFiles.cs index 836be0a0585d..3e59269d5bef 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/V2/Problem/Types/CustomFiles.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/V2/Problem/Types/CustomFiles.cs @@ -68,7 +68,7 @@ public SeedTrace.V2.BasicCustomFiles AsBasic() => : throw new global::System.Exception("CustomFiles.Type is not 'basic'"); /// - /// Returns the value as a if is 'custom', otherwise throws an exception. + /// Returns the value as a if is 'custom', otherwise throws an exception. /// /// Thrown when is not 'custom'. public Dictionary AsCustom() => @@ -125,7 +125,7 @@ public bool TryAsBasic(out SeedTrace.V2.BasicCustomFiles? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsCustom(out Dictionary? value) { diff --git a/seed/csharp-sdk/trace/src/SeedTrace/V2/V3/Problem/Types/CustomFiles.cs b/seed/csharp-sdk/trace/src/SeedTrace/V2/V3/Problem/Types/CustomFiles.cs index 1e09eea80827..3e18da73f6bb 100644 --- a/seed/csharp-sdk/trace/src/SeedTrace/V2/V3/Problem/Types/CustomFiles.cs +++ b/seed/csharp-sdk/trace/src/SeedTrace/V2/V3/Problem/Types/CustomFiles.cs @@ -68,7 +68,7 @@ public SeedTrace.V2.V3.BasicCustomFiles AsBasic() => : throw new global::System.Exception("CustomFiles.Type is not 'basic'"); /// - /// Returns the value as a if is 'custom', otherwise throws an exception. + /// Returns the value as a if is 'custom', otherwise throws an exception. /// /// Thrown when is not 'custom'. public Dictionary AsCustom() => @@ -125,7 +125,7 @@ public bool TryAsBasic(out SeedTrace.V2.V3.BasicCustomFiles? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsCustom(out Dictionary? value) { diff --git a/seed/csharp-sdk/undiscriminated-union-with-response-property/README.md b/seed/csharp-sdk/undiscriminated-union-with-response-property/README.md index 404622987dd2..5790a15ead23 100644 --- a/seed/csharp-sdk/undiscriminated-union-with-response-property/README.md +++ b/seed/csharp-sdk/undiscriminated-union-with-response-property/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.GetUnionAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.GetUnionAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.GetUnionAsync(...); +var parsedData = await client.GetUnionAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty.Test/Utils/OptionalComparer.cs index fa66073d75ca..db66c10c54e0 100644 --- a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/Extensions.cs b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/Extensions.cs index e287f8c6a657..1a83ec118d17 100644 --- a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/Extensions.cs +++ b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/NullableAttribute.cs b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/NullableAttribute.cs index 8b2ace120721..69f2123b74e8 100644 --- a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedUndiscriminatedUnionWithResponseProperty.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedUndiscriminatedUnionWithResponseProperty.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/Optional.cs b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/Optional.cs index 23d26a7b524c..477fc507ae9e 100644 --- a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/Optional.cs +++ b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/OptionalAttribute.cs b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/OptionalAttribute.cs index 3094b86e8c1e..46a829743134 100644 --- a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedUndiscriminatedUnionWithResponseProperty.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/QueryStringBuilder.cs b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/QueryStringBuilder.cs index b3b622afe373..802477f5899d 100644 --- a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/SeedUndiscriminatedUnionWithResponseProperty.csproj b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/SeedUndiscriminatedUnionWithResponseProperty.csproj index 4f10558ef68f..34bbdbf5e5a8 100644 --- a/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/SeedUndiscriminatedUnionWithResponseProperty.csproj +++ b/seed/csharp-sdk/undiscriminated-union-with-response-property/src/SeedUndiscriminatedUnionWithResponseProperty/SeedUndiscriminatedUnionWithResponseProperty.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/undiscriminated-union-with-response-property/fern + https://github.com/undiscriminated-union-with-response-property/fern + git true diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/README.md b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/README.md index 8132d22bd92b..340d7edde47c 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/README.md +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -102,7 +105,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Union.GetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -115,7 +118,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Union.GetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -145,7 +148,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Union.GetAsync(...); +var parsedData = await client.Union.GetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions.Test/Utils/OptionalComparer.cs index b879c42ecce9..67a06bef0f06 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/Extensions.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/Extensions.cs index 6d0307d6b927..b70536bfdddf 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/Extensions.cs +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/NullableAttribute.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/NullableAttribute.cs index 6bc236c31cb8..a032bf1b8c0f 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedUndiscriminatedUnions.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedUndiscriminatedUnions.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/Optional.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/Optional.cs index d332ad331b65..5aea1e14f3cd 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/Optional.cs +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/OptionalAttribute.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/OptionalAttribute.cs index 37582ede96e9..6f8daf4a50a8 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedUndiscriminatedUnions.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/QueryStringBuilder.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/QueryStringBuilder.cs index c075a663535a..682756afd6a1 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/SeedUndiscriminatedUnions.csproj b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/SeedUndiscriminatedUnions.csproj index ee39c5f3376c..89e41bdee661 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/SeedUndiscriminatedUnions.csproj +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/SeedUndiscriminatedUnions.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/undiscriminated-unions/fern + https://github.com/undiscriminated-unions/fern + git true diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/README.md b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/README.md index 8132d22bd92b..340d7edde47c 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/README.md +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -102,7 +105,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Union.GetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -115,7 +118,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Union.GetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -145,7 +148,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Union.GetAsync(...); +var parsedData = await client.Union.GetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/Extensions.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/Extensions.cs index 6d0307d6b927..b70536bfdddf 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/Extensions.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/NullableAttribute.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/NullableAttribute.cs index 6bc236c31cb8..a032bf1b8c0f 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedUndiscriminatedUnions.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedUndiscriminatedUnions.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/Optional.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/Optional.cs index d332ad331b65..5aea1e14f3cd 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/Optional.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/OptionalAttribute.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/OptionalAttribute.cs index 37582ede96e9..6f8daf4a50a8 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedUndiscriminatedUnions.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/QueryStringBuilder.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/QueryStringBuilder.cs index c075a663535a..682756afd6a1 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/SeedUndiscriminatedUnions.csproj b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/SeedUndiscriminatedUnions.csproj index f02a4488476d..c1839e8909f7 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/SeedUndiscriminatedUnions.csproj +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/SeedUndiscriminatedUnions.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/undiscriminated-unions/fern + https://github.com/undiscriminated-unions/fern + git true diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/AliasedObjectUnion.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/AliasedObjectUnion.cs index dc9ed4ee5716..74602a32ee36 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/AliasedObjectUnion.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/AliasedObjectUnion.cs @@ -35,13 +35,13 @@ private AliasedObjectUnion(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a LeafObjectA value. + /// Factory method to create a union from a value. /// public static AliasedObjectUnion FromAliasedLeafA(LeafObjectA value) => new("aliasedLeafA", value); /// - /// Factory method to create a union from a LeafObjectB value. + /// Factory method to create a union from a value. /// public static AliasedObjectUnion FromAliasedLeafB(LeafObjectB value) => new("aliasedLeafB", value); diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/Key.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/Key.cs index da22afc18f85..be5684ee296f 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/Key.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/Key.cs @@ -30,7 +30,7 @@ private Key(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a SeedUndiscriminatedUnions.KeyType value. + /// Factory method to create a union from a value. /// public static Key FromKeyType(SeedUndiscriminatedUnions.KeyType value) => new("keyType", value); diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/MetadataUnion.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/MetadataUnion.cs index 89e362e0e223..a52baa5fce56 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/MetadataUnion.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/MetadataUnion.cs @@ -30,13 +30,13 @@ private MetadataUnion(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a Dictionary? value. + /// Factory method to create a union from a value. /// public static MetadataUnion FromOptionalMetadata(Dictionary? value) => new("optionalMetadata", value); /// - /// Factory method to create a union from a SeedUndiscriminatedUnions.NamedMetadata value. + /// Factory method to create a union from a value. /// public static MetadataUnion FromNamedMetadata(SeedUndiscriminatedUnions.NamedMetadata value) => new("namedMetadata", value); @@ -52,7 +52,7 @@ public static MetadataUnion FromNamedMetadata(SeedUndiscriminatedUnions.NamedMet public bool IsNamedMetadata() => Type == "namedMetadata"; /// - /// Returns the value as a if is 'optionalMetadata', otherwise throws an exception. + /// Returns the value as a if is 'optionalMetadata', otherwise throws an exception. /// /// Thrown when is not 'optionalMetadata'. public Dictionary? AsOptionalMetadata() => @@ -70,7 +70,7 @@ public SeedUndiscriminatedUnions.NamedMetadata AsNamedMetadata() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'namedMetadata'"); /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetOptionalMetadata(out Dictionary? value) { diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/MyUnion.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/MyUnion.cs index 34b38d373c97..12793b2a6748 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/MyUnion.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/MyUnion.cs @@ -33,33 +33,33 @@ private MyUnion(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a string value. + /// Factory method to create a union from a value. /// public static MyUnion FromString(string value) => new("string", value); /// - /// Factory method to create a union from a IEnumerable value. + /// Factory method to create a union from a value. /// public static MyUnion FromListOfString(IEnumerable value) => new("list", value); /// - /// Factory method to create a union from a int value. + /// Factory method to create a union from a value. /// public static MyUnion FromInt(int value) => new("int", value); /// - /// Factory method to create a union from a IEnumerable value. + /// Factory method to create a union from a value. /// public static MyUnion FromListOfInt(IEnumerable value) => new("list_1", value); /// - /// Factory method to create a union from a IEnumerable> value. + /// Factory method to create a union from a IEnumerable<IEnumerable<int>> value. /// public static MyUnion FromListOfListOfInt(IEnumerable> value) => new("list_2", value); /// - /// Factory method to create a union from a HashSet value. + /// Factory method to create a union from a value. /// public static MyUnion FromSetOfString(HashSet value) => new("set", value); @@ -103,7 +103,7 @@ public string AsString() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'string'"); /// - /// Returns the value as a if is 'list', otherwise throws an exception. + /// Returns the value as a if is 'list', otherwise throws an exception. /// /// Thrown when is not 'list'. public IEnumerable AsListOfString() => @@ -121,7 +121,7 @@ public int AsInt() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'int'"); /// - /// Returns the value as a if is 'list_1', otherwise throws an exception. + /// Returns the value as a if is 'list_1', otherwise throws an exception. /// /// Thrown when is not 'list_1'. public IEnumerable AsListOfInt() => @@ -130,7 +130,7 @@ public IEnumerable AsListOfInt() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'list_1'"); /// - /// Returns the value as a if is 'list_2', otherwise throws an exception. + /// Returns the value as a IEnumerable<IEnumerable<int>> if is 'list_2', otherwise throws an exception. /// /// Thrown when is not 'list_2'. public IEnumerable> AsListOfListOfInt() => @@ -139,7 +139,7 @@ public IEnumerable> AsListOfListOfInt() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'list_2'"); /// - /// Returns the value as a if is 'set', otherwise throws an exception. + /// Returns the value as a if is 'set', otherwise throws an exception. /// /// Thrown when is not 'set'. public HashSet AsSetOfString() => @@ -162,7 +162,7 @@ public bool TryGetString(out string? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetListOfString(out IEnumerable? value) { @@ -190,7 +190,7 @@ public bool TryGetInt(out int? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetListOfInt(out IEnumerable? value) { @@ -204,7 +204,7 @@ public bool TryGetListOfInt(out IEnumerable? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a IEnumerable<IEnumerable<int>> and returns true if successful. /// public bool TryGetListOfListOfInt(out IEnumerable>? value) { @@ -218,7 +218,7 @@ public bool TryGetListOfListOfInt(out IEnumerable>? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetSetOfString(out HashSet? value) { diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedObjectUnion.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedObjectUnion.cs index fb772f0c4e56..0db757802cb6 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedObjectUnion.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedObjectUnion.cs @@ -34,13 +34,13 @@ private NestedObjectUnion(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a SeedUndiscriminatedUnions.LeafTypeA value. + /// Factory method to create a union from a value. /// public static NestedObjectUnion FromLeafTypeA(SeedUndiscriminatedUnions.LeafTypeA value) => new("leafTypeA", value); /// - /// Factory method to create a union from a SeedUndiscriminatedUnions.LeafTypeB value. + /// Factory method to create a union from a value. /// public static NestedObjectUnion FromLeafTypeB(SeedUndiscriminatedUnions.LeafTypeB value) => new("leafTypeB", value); diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedUnionL1.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedUnionL1.cs index e2501df4d168..f62184b73159 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedUnionL1.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedUnionL1.cs @@ -33,22 +33,22 @@ private NestedUnionL1(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a int value. + /// Factory method to create a union from a value. /// public static NestedUnionL1 FromInt(int value) => new("int", value); /// - /// Factory method to create a union from a HashSet value. + /// Factory method to create a union from a value. /// public static NestedUnionL1 FromSetOfString(HashSet value) => new("set", value); /// - /// Factory method to create a union from a IEnumerable value. + /// Factory method to create a union from a value. /// public static NestedUnionL1 FromListOfString(IEnumerable value) => new("list", value); /// - /// Factory method to create a union from a SeedUndiscriminatedUnions.NestedUnionL2 value. + /// Factory method to create a union from a value. /// public static NestedUnionL1 FromNestedUnionL2(SeedUndiscriminatedUnions.NestedUnionL2 value) => new("nestedUnionL2", value); @@ -83,7 +83,7 @@ public int AsInt() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'int'"); /// - /// Returns the value as a if is 'set', otherwise throws an exception. + /// Returns the value as a if is 'set', otherwise throws an exception. /// /// Thrown when is not 'set'. public HashSet AsSetOfString() => @@ -92,7 +92,7 @@ public HashSet AsSetOfString() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'set'"); /// - /// Returns the value as a if is 'list', otherwise throws an exception. + /// Returns the value as a if is 'list', otherwise throws an exception. /// /// Thrown when is not 'list'. public IEnumerable AsListOfString() => @@ -124,7 +124,7 @@ public bool TryGetInt(out int? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetSetOfString(out HashSet? value) { @@ -138,7 +138,7 @@ public bool TryGetSetOfString(out HashSet? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetListOfString(out IEnumerable? value) { diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedUnionL2.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedUnionL2.cs index 2a462df64cfd..e685955963f9 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedUnionL2.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedUnionL2.cs @@ -33,17 +33,17 @@ private NestedUnionL2(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a bool value. + /// Factory method to create a union from a value. /// public static NestedUnionL2 FromBool(bool value) => new("bool", value); /// - /// Factory method to create a union from a HashSet value. + /// Factory method to create a union from a value. /// public static NestedUnionL2 FromSetOfString(HashSet value) => new("set", value); /// - /// Factory method to create a union from a IEnumerable value. + /// Factory method to create a union from a value. /// public static NestedUnionL2 FromListOfString(IEnumerable value) => new("list", value); @@ -72,7 +72,7 @@ public bool AsBool() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'bool'"); /// - /// Returns the value as a if is 'set', otherwise throws an exception. + /// Returns the value as a if is 'set', otherwise throws an exception. /// /// Thrown when is not 'set'. public HashSet AsSetOfString() => @@ -81,7 +81,7 @@ public HashSet AsSetOfString() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'set'"); /// - /// Returns the value as a if is 'list', otherwise throws an exception. + /// Returns the value as a if is 'list', otherwise throws an exception. /// /// Thrown when is not 'list'. public IEnumerable AsListOfString() => @@ -104,7 +104,7 @@ public bool TryGetBool(out bool? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetSetOfString(out HashSet? value) { @@ -118,7 +118,7 @@ public bool TryGetSetOfString(out HashSet? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetListOfString(out IEnumerable? value) { diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedUnionRoot.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedUnionRoot.cs index 0c6f1a4ebb7d..c4eeb064ecb5 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedUnionRoot.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedUnionRoot.cs @@ -33,17 +33,17 @@ private NestedUnionRoot(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a string value. + /// Factory method to create a union from a value. /// public static NestedUnionRoot FromString(string value) => new("string", value); /// - /// Factory method to create a union from a IEnumerable value. + /// Factory method to create a union from a value. /// public static NestedUnionRoot FromListOfString(IEnumerable value) => new("list", value); /// - /// Factory method to create a union from a SeedUndiscriminatedUnions.NestedUnionL1 value. + /// Factory method to create a union from a value. /// public static NestedUnionRoot FromNestedUnionL1( SeedUndiscriminatedUnions.NestedUnionL1 value @@ -74,7 +74,7 @@ public string AsString() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'string'"); /// - /// Returns the value as a if is 'list', otherwise throws an exception. + /// Returns the value as a if is 'list', otherwise throws an exception. /// /// Thrown when is not 'list'. public IEnumerable AsListOfString() => @@ -106,7 +106,7 @@ public bool TryGetString(out string? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetListOfString(out IEnumerable? value) { diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/OuterNestedUnion.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/OuterNestedUnion.cs index 83c1b45681f8..73445ebb06d4 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/OuterNestedUnion.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/OuterNestedUnion.cs @@ -34,12 +34,12 @@ private OuterNestedUnion(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a string value. + /// Factory method to create a union from a value. /// public static OuterNestedUnion FromString(string value) => new("string", value); /// - /// Factory method to create a union from a SeedUndiscriminatedUnions.WrapperObject value. + /// Factory method to create a union from a value. /// public static OuterNestedUnion FromWrapperObject( SeedUndiscriminatedUnions.WrapperObject value diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/PaymentMethodUnion.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/PaymentMethodUnion.cs index 2a8e92069b86..e50bacbca026 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/PaymentMethodUnion.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/PaymentMethodUnion.cs @@ -34,14 +34,14 @@ private PaymentMethodUnion(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a SeedUndiscriminatedUnions.TokenizeCard value. + /// Factory method to create a union from a value. /// public static PaymentMethodUnion FromTokenizeCard( SeedUndiscriminatedUnions.TokenizeCard value ) => new("tokenizeCard", value); /// - /// Factory method to create a union from a SeedUndiscriminatedUnions.ConvertToken value. + /// Factory method to create a union from a value. /// public static PaymentMethodUnion FromConvertToken( SeedUndiscriminatedUnions.ConvertToken value diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithBaseProperties.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithBaseProperties.cs index c879a53ea845..6d0435838c68 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithBaseProperties.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithBaseProperties.cs @@ -34,14 +34,14 @@ private UnionWithBaseProperties(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a SeedUndiscriminatedUnions.NamedMetadata value. + /// Factory method to create a union from a value. /// public static UnionWithBaseProperties FromNamedMetadata( SeedUndiscriminatedUnions.NamedMetadata value ) => new("namedMetadata", value); /// - /// Factory method to create a union from a Dictionary? value. + /// Factory method to create a union from a value. /// public static UnionWithBaseProperties FromOptionalMetadata( Dictionary? value @@ -67,7 +67,7 @@ public SeedUndiscriminatedUnions.NamedMetadata AsNamedMetadata() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'namedMetadata'"); /// - /// Returns the value as a if is 'optionalMetadata', otherwise throws an exception. + /// Returns the value as a if is 'optionalMetadata', otherwise throws an exception. /// /// Thrown when is not 'optionalMetadata'. public Dictionary? AsOptionalMetadata() => @@ -90,7 +90,7 @@ public bool TryGetNamedMetadata(out SeedUndiscriminatedUnions.NamedMetadata? val } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetOptionalMetadata(out Dictionary? value) { diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithDuplicateTypes.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithDuplicateTypes.cs index 1ecd4f8ee69a..b5611af281b1 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithDuplicateTypes.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithDuplicateTypes.cs @@ -33,23 +33,23 @@ private UnionWithDuplicateTypes(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a string value. + /// Factory method to create a union from a value. /// public static UnionWithDuplicateTypes FromString(string value) => new("string", value); /// - /// Factory method to create a union from a IEnumerable value. + /// Factory method to create a union from a value. /// public static UnionWithDuplicateTypes FromListOfString(IEnumerable value) => new("list", value); /// - /// Factory method to create a union from a int value. + /// Factory method to create a union from a value. /// public static UnionWithDuplicateTypes FromInt(int value) => new("int", value); /// - /// Factory method to create a union from a HashSet value. + /// Factory method to create a union from a value. /// public static UnionWithDuplicateTypes FromSetOfString(HashSet value) => new("set", value); @@ -84,7 +84,7 @@ public string AsString() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'string'"); /// - /// Returns the value as a if is 'list', otherwise throws an exception. + /// Returns the value as a if is 'list', otherwise throws an exception. /// /// Thrown when is not 'list'. public IEnumerable AsListOfString() => @@ -102,7 +102,7 @@ public int AsInt() => : throw new SeedUndiscriminatedUnionsException("Union type is not 'int'"); /// - /// Returns the value as a if is 'set', otherwise throws an exception. + /// Returns the value as a if is 'set', otherwise throws an exception. /// /// Thrown when is not 'set'. public HashSet AsSetOfString() => @@ -125,7 +125,7 @@ public bool TryGetString(out string? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetListOfString(out IEnumerable? value) { @@ -153,7 +153,7 @@ public bool TryGetInt(out int? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryGetSetOfString(out HashSet? value) { diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithIdenticalPrimitives.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithIdenticalPrimitives.cs index 7e4402567513..b090d15d9818 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithIdenticalPrimitives.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithIdenticalPrimitives.cs @@ -33,17 +33,17 @@ private UnionWithIdenticalPrimitives(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a int value. + /// Factory method to create a union from a value. /// public static UnionWithIdenticalPrimitives FromInt(int value) => new("int", value); /// - /// Factory method to create a union from a double value. + /// Factory method to create a union from a value. /// public static UnionWithIdenticalPrimitives FromDouble(double value) => new("double", value); /// - /// Factory method to create a union from a string value. + /// Factory method to create a union from a value. /// public static UnionWithIdenticalPrimitives FromString(string value) => new("string", value); diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithIdenticalStrings.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithIdenticalStrings.cs index a74b0577a94f..83191c22a4b9 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithIdenticalStrings.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithIdenticalStrings.cs @@ -34,7 +34,7 @@ private UnionWithIdenticalStrings(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a string value. + /// Factory method to create a union from a value. /// public static UnionWithIdenticalStrings FromString(string value) => new("string", value); diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithReservedNames.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithReservedNames.cs index c19a410f7b1f..f21170c09b26 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithReservedNames.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithReservedNames.cs @@ -43,7 +43,7 @@ private UnionWithReservedNames(string type, object? value) public static UnionWithReservedNames FromValueMember() => new("value", "value"); /// - /// Factory method to create a union from a string value. + /// Factory method to create a union from a value. /// public static UnionWithReservedNames FromString(string value) => new("string", value); diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithTypeAliases.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithTypeAliases.cs index 5476b88dcbe3..05ee09ae4433 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithTypeAliases.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/UnionWithTypeAliases.cs @@ -38,17 +38,17 @@ private UnionWithTypeAliases(string type, object? value) public object? Value { get; internal set; } /// - /// Factory method to create a union from a string value. + /// Factory method to create a union from a value. /// public static UnionWithTypeAliases FromString(string value) => new("string", value); /// - /// Factory method to create a union from a string value. + /// Factory method to create a union from a value. /// public static UnionWithTypeAliases FromUserId(string value) => new("userId", value); /// - /// Factory method to create a union from a string value. + /// Factory method to create a union from a value. /// public static UnionWithTypeAliases FromName(string value) => new("name", value); diff --git a/seed/csharp-sdk/union-query-parameters/README.md b/seed/csharp-sdk/union-query-parameters/README.md index 112adb95b0be..7924559ef9a9 100644 --- a/seed/csharp-sdk/union-query-parameters/README.md +++ b/seed/csharp-sdk/union-query-parameters/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -104,7 +107,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Events.SubscribeAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -117,7 +120,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Events.SubscribeAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -147,7 +150,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Events.SubscribeAsync(...); +var parsedData = await client.Events.SubscribeAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters.Test/Utils/OptionalComparer.cs index c012648c72a3..9b44d00ebeb2 100644 --- a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/Extensions.cs b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/Extensions.cs index 2fc1a607f670..b3cc861776af 100644 --- a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/Extensions.cs +++ b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/NullableAttribute.cs b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/NullableAttribute.cs index 2579326bf27f..9973918d8f42 100644 --- a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedUnionQueryParameters.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedUnionQueryParameters.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/Optional.cs b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/Optional.cs index 227d39e9a051..2d28924fd187 100644 --- a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/Optional.cs +++ b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/OptionalAttribute.cs b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/OptionalAttribute.cs index 27e8e09a449f..a92d3f177991 100644 --- a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedUnionQueryParameters.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/QueryStringBuilder.cs b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/QueryStringBuilder.cs index 5bec7b302388..e9b0ef87089e 100644 --- a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/SeedUnionQueryParameters.csproj b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/SeedUnionQueryParameters.csproj index fba54a292500..f52103e5fa02 100644 --- a/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/SeedUnionQueryParameters.csproj +++ b/seed/csharp-sdk/union-query-parameters/src/SeedUnionQueryParameters/SeedUnionQueryParameters.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/union-query-parameters/fern + https://github.com/union-query-parameters/fern + git true diff --git a/seed/csharp-sdk/unions-with-local-date/README.md b/seed/csharp-sdk/unions-with-local-date/README.md index 83db0788a72b..b75c2ba32a2b 100644 --- a/seed/csharp-sdk/unions-with-local-date/README.md +++ b/seed/csharp-sdk/unions-with-local-date/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Bigunion.GetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Bigunion.GetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Bigunion.GetAsync(...); +var parsedData = await client.Bigunion.GetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions.Test/Utils/OptionalComparer.cs index f7910c2e6e84..13b951e8ab0c 100644 --- a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/Extensions.cs b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/Extensions.cs index f6053c07a11d..d09b48f602c4 100644 --- a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/Extensions.cs +++ b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/NullableAttribute.cs b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/NullableAttribute.cs index c51a087df378..ef09552d6620 100644 --- a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedUnions.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedUnions.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/Optional.cs b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/Optional.cs index 7f3dcde8f061..7ccc6436f5ff 100644 --- a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/Optional.cs +++ b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/OptionalAttribute.cs b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/OptionalAttribute.cs index 77845b5a0bb5..f8e4ddc6f78b 100644 --- a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedUnions.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/QueryStringBuilder.cs b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/QueryStringBuilder.cs index 215735e0d970..fe0559b48cda 100644 --- a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/SeedUnions.csproj b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/SeedUnions.csproj index 1a38a0ba56d1..ac74ec8694de 100644 --- a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/SeedUnions.csproj +++ b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/SeedUnions.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/unions-with-local-date/fern + https://github.com/unions-with-local-date/fern + git true diff --git a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Types/Types/UnionWithMultipleNoProperties.cs b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Types/Types/UnionWithMultipleNoProperties.cs index 5273acd14bcb..2482c6f73c52 100644 --- a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Types/Types/UnionWithMultipleNoProperties.cs +++ b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Types/Types/UnionWithMultipleNoProperties.cs @@ -81,7 +81,7 @@ public SeedUnions.Foo AsFoo() => : throw new global::System.Exception("UnionWithMultipleNoProperties.Type is not 'foo'"); /// - /// Returns the value as a if is 'empty1', otherwise throws an exception. + /// Returns the value as a if is 'empty1', otherwise throws an exception. /// /// Thrown when is not 'empty1'. public object? AsEmpty1() => @@ -92,7 +92,7 @@ public SeedUnions.Foo AsFoo() => ); /// - /// Returns the value as a if is 'empty2', otherwise throws an exception. + /// Returns the value as a if is 'empty2', otherwise throws an exception. /// /// Thrown when is not 'empty2'. public object? AsEmpty2() => @@ -157,7 +157,7 @@ public bool TryAsFoo(out SeedUnions.Foo? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsEmpty1(out object? value) { @@ -171,7 +171,7 @@ public bool TryAsEmpty1(out object? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsEmpty2(out object? value) { diff --git a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Types/Types/UnionWithNoProperties.cs b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Types/Types/UnionWithNoProperties.cs index f1be6d448e8c..0097d7cc6200 100644 --- a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Types/Types/UnionWithNoProperties.cs +++ b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Types/Types/UnionWithNoProperties.cs @@ -67,7 +67,7 @@ public SeedUnions.Foo AsFoo() => : throw new global::System.Exception("UnionWithNoProperties.Type is not 'foo'"); /// - /// Returns the value as a if is 'empty', otherwise throws an exception. + /// Returns the value as a if is 'empty', otherwise throws an exception. /// /// Thrown when is not 'empty'. public object? AsEmpty() => @@ -124,7 +124,7 @@ public bool TryAsFoo(out SeedUnions.Foo? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsEmpty(out object? value) { diff --git a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Types/Types/UnionWithOptionalTime.cs b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Types/Types/UnionWithOptionalTime.cs index 0b42d7213c90..c9920c39fc71 100644 --- a/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Types/Types/UnionWithOptionalTime.cs +++ b/seed/csharp-sdk/unions-with-local-date/src/SeedUnions/Types/Types/UnionWithOptionalTime.cs @@ -58,7 +58,7 @@ public UnionWithOptionalTime(UnionWithOptionalTime.Datetime value) public bool IsDatetime => Type == "datetime"; /// - /// Returns the value as a if is 'date', otherwise throws an exception. + /// Returns the value as a if is 'date', otherwise throws an exception. /// /// Thrown when is not 'date'. public DateOnly? AsDate() => @@ -67,7 +67,7 @@ public UnionWithOptionalTime(UnionWithOptionalTime.Datetime value) : throw new global::System.Exception("UnionWithOptionalTime.Type is not 'date'"); /// - /// Returns the value as a if is 'datetime', otherwise throws an exception. + /// Returns the value as a if is 'datetime', otherwise throws an exception. /// /// Thrown when is not 'datetime'. public DateTime? AsDatetime() => @@ -110,7 +110,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsDate(out DateOnly? value) { @@ -124,7 +124,7 @@ public bool TryAsDate(out DateOnly? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsDatetime(out DateTime? value) { diff --git a/seed/csharp-sdk/unions/no-custom-config/README.md b/seed/csharp-sdk/unions/no-custom-config/README.md index 4d307f504c3a..90ca336db76b 100644 --- a/seed/csharp-sdk/unions/no-custom-config/README.md +++ b/seed/csharp-sdk/unions/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Bigunion.GetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Bigunion.GetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Bigunion.GetAsync(...); +var parsedData = await client.Bigunion.GetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions.Test/Utils/OptionalComparer.cs index f7910c2e6e84..13b951e8ab0c 100644 --- a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/Extensions.cs b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/Extensions.cs index f6053c07a11d..d09b48f602c4 100644 --- a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/Extensions.cs +++ b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/NullableAttribute.cs b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/NullableAttribute.cs index c51a087df378..ef09552d6620 100644 --- a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedUnions.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedUnions.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/Optional.cs b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/Optional.cs index 7f3dcde8f061..7ccc6436f5ff 100644 --- a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/Optional.cs +++ b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/OptionalAttribute.cs b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/OptionalAttribute.cs index 77845b5a0bb5..f8e4ddc6f78b 100644 --- a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedUnions.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/QueryStringBuilder.cs b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/QueryStringBuilder.cs index 215735e0d970..fe0559b48cda 100644 --- a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/SeedUnions.csproj b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/SeedUnions.csproj index 1c467dd4e9f4..f5ce9a7c4c74 100644 --- a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/SeedUnions.csproj +++ b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/SeedUnions.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/unions/fern + https://github.com/unions/fern + git true diff --git a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithMultipleNoProperties.cs b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithMultipleNoProperties.cs index 5273acd14bcb..2482c6f73c52 100644 --- a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithMultipleNoProperties.cs +++ b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithMultipleNoProperties.cs @@ -81,7 +81,7 @@ public SeedUnions.Foo AsFoo() => : throw new global::System.Exception("UnionWithMultipleNoProperties.Type is not 'foo'"); /// - /// Returns the value as a if is 'empty1', otherwise throws an exception. + /// Returns the value as a if is 'empty1', otherwise throws an exception. /// /// Thrown when is not 'empty1'. public object? AsEmpty1() => @@ -92,7 +92,7 @@ public SeedUnions.Foo AsFoo() => ); /// - /// Returns the value as a if is 'empty2', otherwise throws an exception. + /// Returns the value as a if is 'empty2', otherwise throws an exception. /// /// Thrown when is not 'empty2'. public object? AsEmpty2() => @@ -157,7 +157,7 @@ public bool TryAsFoo(out SeedUnions.Foo? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsEmpty1(out object? value) { @@ -171,7 +171,7 @@ public bool TryAsEmpty1(out object? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsEmpty2(out object? value) { diff --git a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithNoProperties.cs b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithNoProperties.cs index f1be6d448e8c..0097d7cc6200 100644 --- a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithNoProperties.cs +++ b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithNoProperties.cs @@ -67,7 +67,7 @@ public SeedUnions.Foo AsFoo() => : throw new global::System.Exception("UnionWithNoProperties.Type is not 'foo'"); /// - /// Returns the value as a if is 'empty', otherwise throws an exception. + /// Returns the value as a if is 'empty', otherwise throws an exception. /// /// Thrown when is not 'empty'. public object? AsEmpty() => @@ -124,7 +124,7 @@ public bool TryAsFoo(out SeedUnions.Foo? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsEmpty(out object? value) { diff --git a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithNullableReference.cs b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithNullableReference.cs index 4ba319c54cd7..0ee56300148d 100644 --- a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithNullableReference.cs +++ b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithNullableReference.cs @@ -58,7 +58,7 @@ public UnionWithNullableReference(UnionWithNullableReference.Bar value) public bool IsBar => Type == "bar"; /// - /// Returns the value as a if is 'foo', otherwise throws an exception. + /// Returns the value as a if is 'foo', otherwise throws an exception. /// /// Thrown when is not 'foo'. public Foo? AsFoo() => @@ -67,7 +67,7 @@ public UnionWithNullableReference(UnionWithNullableReference.Bar value) : throw new global::System.Exception("UnionWithNullableReference.Type is not 'foo'"); /// - /// Returns the value as a if is 'bar', otherwise throws an exception. + /// Returns the value as a if is 'bar', otherwise throws an exception. /// /// Thrown when is not 'bar'. public Bar? AsBar() => @@ -102,7 +102,7 @@ public void Visit(Action onFoo, Action onBar, Action - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsFoo(out Foo? value) { @@ -116,7 +116,7 @@ public bool TryAsFoo(out Foo? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsBar(out Bar? value) { diff --git a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithOptionalReference.cs b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithOptionalReference.cs index cc11d6c0e2ca..2d58dc45ffa7 100644 --- a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithOptionalReference.cs +++ b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithOptionalReference.cs @@ -58,7 +58,7 @@ public UnionWithOptionalReference(UnionWithOptionalReference.Bar value) public bool IsBar => Type == "bar"; /// - /// Returns the value as a if is 'foo', otherwise throws an exception. + /// Returns the value as a if is 'foo', otherwise throws an exception. /// /// Thrown when is not 'foo'. public Foo? AsFoo() => @@ -67,7 +67,7 @@ public UnionWithOptionalReference(UnionWithOptionalReference.Bar value) : throw new global::System.Exception("UnionWithOptionalReference.Type is not 'foo'"); /// - /// Returns the value as a if is 'bar', otherwise throws an exception. + /// Returns the value as a if is 'bar', otherwise throws an exception. /// /// Thrown when is not 'bar'. public Bar? AsBar() => @@ -102,7 +102,7 @@ public void Visit(Action onFoo, Action onBar, Action - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsFoo(out Foo? value) { @@ -116,7 +116,7 @@ public bool TryAsFoo(out Foo? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsBar(out Bar? value) { diff --git a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithOptionalTime.cs b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithOptionalTime.cs index 0b42d7213c90..c9920c39fc71 100644 --- a/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithOptionalTime.cs +++ b/seed/csharp-sdk/unions/no-custom-config/src/SeedUnions/Types/Types/UnionWithOptionalTime.cs @@ -58,7 +58,7 @@ public UnionWithOptionalTime(UnionWithOptionalTime.Datetime value) public bool IsDatetime => Type == "datetime"; /// - /// Returns the value as a if is 'date', otherwise throws an exception. + /// Returns the value as a if is 'date', otherwise throws an exception. /// /// Thrown when is not 'date'. public DateOnly? AsDate() => @@ -67,7 +67,7 @@ public UnionWithOptionalTime(UnionWithOptionalTime.Datetime value) : throw new global::System.Exception("UnionWithOptionalTime.Type is not 'date'"); /// - /// Returns the value as a if is 'datetime', otherwise throws an exception. + /// Returns the value as a if is 'datetime', otherwise throws an exception. /// /// Thrown when is not 'datetime'. public DateTime? AsDatetime() => @@ -110,7 +110,7 @@ public void Visit( } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsDate(out DateOnly? value) { @@ -124,7 +124,7 @@ public bool TryAsDate(out DateOnly? value) } /// - /// Attempts to cast the value to a and returns true if successful. + /// Attempts to cast the value to a and returns true if successful. /// public bool TryAsDatetime(out DateTime? value) { diff --git a/seed/csharp-sdk/unions/no-discriminated-unions/README.md b/seed/csharp-sdk/unions/no-discriminated-unions/README.md index 4d307f504c3a..90ca336db76b 100644 --- a/seed/csharp-sdk/unions/no-discriminated-unions/README.md +++ b/seed/csharp-sdk/unions/no-discriminated-unions/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Bigunion.GetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Bigunion.GetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Bigunion.GetAsync(...); +var parsedData = await client.Bigunion.GetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions.Test/Utils/OptionalComparer.cs index f7910c2e6e84..13b951e8ab0c 100644 --- a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/Extensions.cs b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/Extensions.cs index f6053c07a11d..d09b48f602c4 100644 --- a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/Extensions.cs +++ b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/NullableAttribute.cs b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/NullableAttribute.cs index c51a087df378..ef09552d6620 100644 --- a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedUnions.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedUnions.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/Optional.cs b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/Optional.cs index 7f3dcde8f061..7ccc6436f5ff 100644 --- a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/Optional.cs +++ b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/OptionalAttribute.cs b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/OptionalAttribute.cs index 77845b5a0bb5..f8e4ddc6f78b 100644 --- a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedUnions.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/QueryStringBuilder.cs b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/QueryStringBuilder.cs index 215735e0d970..fe0559b48cda 100644 --- a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/SeedUnions.csproj b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/SeedUnions.csproj index 1c467dd4e9f4..f5ce9a7c4c74 100644 --- a/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/SeedUnions.csproj +++ b/seed/csharp-sdk/unions/no-discriminated-unions/src/SeedUnions/SeedUnions.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/unions/fern + https://github.com/unions/fern + git true diff --git a/seed/csharp-sdk/unknown/README.md b/seed/csharp-sdk/unknown/README.md index 5abae0f0d84a..d28cfe51d9f3 100644 --- a/seed/csharp-sdk/unknown/README.md +++ b/seed/csharp-sdk/unknown/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Unknown.PostAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Unknown.PostAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Unknown.PostAsync(...); +var parsedData = await client.Unknown.PostAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny.Test/Utils/OptionalComparer.cs index 9913ea3fed54..ce284768f92c 100644 --- a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/Extensions.cs b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/Extensions.cs index 6c4df7cd88c4..4810dc6f2bc8 100644 --- a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/Extensions.cs +++ b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/NullableAttribute.cs b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/NullableAttribute.cs index 2acda5016d1d..31611e0398d9 100644 --- a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedUnknownAsAny.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedUnknownAsAny.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/Optional.cs b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/Optional.cs index 0379dadb901b..316c62e3283e 100644 --- a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/Optional.cs +++ b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/OptionalAttribute.cs b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/OptionalAttribute.cs index 45fd4b77f3f0..e94427ba5d11 100644 --- a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedUnknownAsAny.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/QueryStringBuilder.cs b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/QueryStringBuilder.cs index f6125a5b432a..8ea1e275fcdb 100644 --- a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/SeedUnknownAsAny.csproj b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/SeedUnknownAsAny.csproj index d7bf8852f362..8c57d54f900d 100644 --- a/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/SeedUnknownAsAny.csproj +++ b/seed/csharp-sdk/unknown/src/SeedUnknownAsAny/SeedUnknownAsAny.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/unknown/fern + https://github.com/unknown/fern + git true diff --git a/seed/csharp-sdk/url-form-encoded/no-custom-config/README.md b/seed/csharp-sdk/url-form-encoded/no-custom-config/README.md index 3ad1d4b9b139..5024ae249eae 100644 --- a/seed/csharp-sdk/url-form-encoded/no-custom-config/README.md +++ b/seed/csharp-sdk/url-form-encoded/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.SubmitFormDataAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.SubmitFormDataAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.SubmitFormDataAsync(...); +var parsedData = await client.SubmitFormDataAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/SeedApi.csproj index 78b9080c3dc8..6b040ceb5d15 100644 --- a/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/url-form-encoded/no-custom-config/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/url-form-encoded/fern + https://github.com/url-form-encoded/fern + git true diff --git a/seed/csharp-sdk/validation/README.md b/seed/csharp-sdk/validation/README.md index 283985c56fc3..eb84e6958b35 100644 --- a/seed/csharp-sdk/validation/README.md +++ b/seed/csharp-sdk/validation/README.md @@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -110,7 +113,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.CreateAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -123,7 +126,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.CreateAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -153,7 +156,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.CreateAsync(...); +var parsedData = await client.CreateAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/validation/src/SeedValidation.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/validation/src/SeedValidation.Test/Utils/OptionalComparer.cs index 9c5a8547ae55..cd3cb9f1ea24 100644 --- a/seed/csharp-sdk/validation/src/SeedValidation.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/validation/src/SeedValidation.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/validation/src/SeedValidation/Core/Extensions.cs b/seed/csharp-sdk/validation/src/SeedValidation/Core/Extensions.cs index 1699b10a687a..53a4f849ea7a 100644 --- a/seed/csharp-sdk/validation/src/SeedValidation/Core/Extensions.cs +++ b/seed/csharp-sdk/validation/src/SeedValidation/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/validation/src/SeedValidation/Core/NullableAttribute.cs b/seed/csharp-sdk/validation/src/SeedValidation/Core/NullableAttribute.cs index 98dad7a43ccb..f48cab0bfe43 100644 --- a/seed/csharp-sdk/validation/src/SeedValidation/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/validation/src/SeedValidation/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedValidation.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedValidation.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/validation/src/SeedValidation/Core/Optional.cs b/seed/csharp-sdk/validation/src/SeedValidation/Core/Optional.cs index a26c9470c9d0..220d9f809552 100644 --- a/seed/csharp-sdk/validation/src/SeedValidation/Core/Optional.cs +++ b/seed/csharp-sdk/validation/src/SeedValidation/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/validation/src/SeedValidation/Core/OptionalAttribute.cs b/seed/csharp-sdk/validation/src/SeedValidation/Core/OptionalAttribute.cs index 8d293430f88a..2cc37ae5d9cf 100644 --- a/seed/csharp-sdk/validation/src/SeedValidation/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/validation/src/SeedValidation/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedValidation.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/validation/src/SeedValidation/Core/QueryStringBuilder.cs b/seed/csharp-sdk/validation/src/SeedValidation/Core/QueryStringBuilder.cs index dbe3d6bac2b2..7a889b9d8cd0 100644 --- a/seed/csharp-sdk/validation/src/SeedValidation/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/validation/src/SeedValidation/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/validation/src/SeedValidation/SeedValidation.csproj b/seed/csharp-sdk/validation/src/SeedValidation/SeedValidation.csproj index e5d8be4788b3..dc71595f05c2 100644 --- a/seed/csharp-sdk/validation/src/SeedValidation/SeedValidation.csproj +++ b/seed/csharp-sdk/validation/src/SeedValidation/SeedValidation.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/validation/fern + https://github.com/validation/fern + git true diff --git a/seed/csharp-sdk/variables/README.md b/seed/csharp-sdk/variables/README.md index 360bc38cbbe0..fba659924721 100644 --- a/seed/csharp-sdk/variables/README.md +++ b/seed/csharp-sdk/variables/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Service.PostAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Service.PostAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Service.PostAsync(...); +var parsedData = await client.Service.PostAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/variables/src/SeedVariables.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/variables/src/SeedVariables.Test/Utils/OptionalComparer.cs index b786641eca60..6a1267939906 100644 --- a/seed/csharp-sdk/variables/src/SeedVariables.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/variables/src/SeedVariables.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/variables/src/SeedVariables/Core/Extensions.cs b/seed/csharp-sdk/variables/src/SeedVariables/Core/Extensions.cs index c15b7c88b7b6..125c832c8c2f 100644 --- a/seed/csharp-sdk/variables/src/SeedVariables/Core/Extensions.cs +++ b/seed/csharp-sdk/variables/src/SeedVariables/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/variables/src/SeedVariables/Core/NullableAttribute.cs b/seed/csharp-sdk/variables/src/SeedVariables/Core/NullableAttribute.cs index ed7e3047e08a..0f52b12f4946 100644 --- a/seed/csharp-sdk/variables/src/SeedVariables/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/variables/src/SeedVariables/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedVariables.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedVariables.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/variables/src/SeedVariables/Core/Optional.cs b/seed/csharp-sdk/variables/src/SeedVariables/Core/Optional.cs index cd31d12a3185..d3111156f3a9 100644 --- a/seed/csharp-sdk/variables/src/SeedVariables/Core/Optional.cs +++ b/seed/csharp-sdk/variables/src/SeedVariables/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/variables/src/SeedVariables/Core/OptionalAttribute.cs b/seed/csharp-sdk/variables/src/SeedVariables/Core/OptionalAttribute.cs index 22541a538f79..ace2b0b596f8 100644 --- a/seed/csharp-sdk/variables/src/SeedVariables/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/variables/src/SeedVariables/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedVariables.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/variables/src/SeedVariables/Core/QueryStringBuilder.cs b/seed/csharp-sdk/variables/src/SeedVariables/Core/QueryStringBuilder.cs index a3fcf4e4477c..a5743f97ce93 100644 --- a/seed/csharp-sdk/variables/src/SeedVariables/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/variables/src/SeedVariables/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/variables/src/SeedVariables/SeedVariables.csproj b/seed/csharp-sdk/variables/src/SeedVariables/SeedVariables.csproj index ac79dc24d30c..d5125afcc29c 100644 --- a/seed/csharp-sdk/variables/src/SeedVariables/SeedVariables.csproj +++ b/seed/csharp-sdk/variables/src/SeedVariables/SeedVariables.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/variables/fern + https://github.com/variables/fern + git true diff --git a/seed/csharp-sdk/version-no-default/README.md b/seed/csharp-sdk/version-no-default/README.md index 618f0e4062c4..2370f8deadae 100644 --- a/seed/csharp-sdk/version-no-default/README.md +++ b/seed/csharp-sdk/version-no-default/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.GetUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.GetUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.GetUserAsync(...); +var parsedData = await client.User.GetUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/version-no-default/src/SeedVersion.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/version-no-default/src/SeedVersion.Test/Utils/OptionalComparer.cs index 685203260fd6..bdf34590cd38 100644 --- a/seed/csharp-sdk/version-no-default/src/SeedVersion.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/version-no-default/src/SeedVersion.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/Extensions.cs b/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/Extensions.cs index f24545014a07..cef56002105a 100644 --- a/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/Extensions.cs +++ b/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/NullableAttribute.cs b/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/NullableAttribute.cs index f8eddbbbbfa1..2dd67e573bee 100644 --- a/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedVersion.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedVersion.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/Optional.cs b/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/Optional.cs index 144800fb140e..cf587430d779 100644 --- a/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/Optional.cs +++ b/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/OptionalAttribute.cs b/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/OptionalAttribute.cs index 171ce977566a..fdbe11819c5f 100644 --- a/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedVersion.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/QueryStringBuilder.cs b/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/QueryStringBuilder.cs index 93fa0a4af7ce..00124e6052d2 100644 --- a/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/version-no-default/src/SeedVersion/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/version-no-default/src/SeedVersion/SeedVersion.csproj b/seed/csharp-sdk/version-no-default/src/SeedVersion/SeedVersion.csproj index 67cac58993de..f9133296f188 100644 --- a/seed/csharp-sdk/version-no-default/src/SeedVersion/SeedVersion.csproj +++ b/seed/csharp-sdk/version-no-default/src/SeedVersion/SeedVersion.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/version-no-default/fern + https://github.com/version-no-default/fern + git true diff --git a/seed/csharp-sdk/version/README.md b/seed/csharp-sdk/version/README.md index 43a80b03c18b..a2ba70ef58ec 100644 --- a/seed/csharp-sdk/version/README.md +++ b/seed/csharp-sdk/version/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.User.GetUserAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.User.GetUserAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.User.GetUserAsync(...); +var parsedData = await client.User.GetUserAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/version/src/SeedVersion.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/version/src/SeedVersion.Test/Utils/OptionalComparer.cs index 685203260fd6..bdf34590cd38 100644 --- a/seed/csharp-sdk/version/src/SeedVersion.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/version/src/SeedVersion.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/version/src/SeedVersion/Core/Extensions.cs b/seed/csharp-sdk/version/src/SeedVersion/Core/Extensions.cs index f24545014a07..cef56002105a 100644 --- a/seed/csharp-sdk/version/src/SeedVersion/Core/Extensions.cs +++ b/seed/csharp-sdk/version/src/SeedVersion/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/version/src/SeedVersion/Core/NullableAttribute.cs b/seed/csharp-sdk/version/src/SeedVersion/Core/NullableAttribute.cs index f8eddbbbbfa1..2dd67e573bee 100644 --- a/seed/csharp-sdk/version/src/SeedVersion/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/version/src/SeedVersion/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedVersion.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedVersion.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/version/src/SeedVersion/Core/Optional.cs b/seed/csharp-sdk/version/src/SeedVersion/Core/Optional.cs index 144800fb140e..cf587430d779 100644 --- a/seed/csharp-sdk/version/src/SeedVersion/Core/Optional.cs +++ b/seed/csharp-sdk/version/src/SeedVersion/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/version/src/SeedVersion/Core/OptionalAttribute.cs b/seed/csharp-sdk/version/src/SeedVersion/Core/OptionalAttribute.cs index 171ce977566a..fdbe11819c5f 100644 --- a/seed/csharp-sdk/version/src/SeedVersion/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/version/src/SeedVersion/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedVersion.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/version/src/SeedVersion/Core/QueryStringBuilder.cs b/seed/csharp-sdk/version/src/SeedVersion/Core/QueryStringBuilder.cs index 93fa0a4af7ce..00124e6052d2 100644 --- a/seed/csharp-sdk/version/src/SeedVersion/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/version/src/SeedVersion/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/version/src/SeedVersion/SeedVersion.csproj b/seed/csharp-sdk/version/src/SeedVersion/SeedVersion.csproj index 9bc0426901a3..4f3f66226069 100644 --- a/seed/csharp-sdk/version/src/SeedVersion/SeedVersion.csproj +++ b/seed/csharp-sdk/version/src/SeedVersion/SeedVersion.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/version/fern + https://github.com/version/fern + git true diff --git a/seed/csharp-sdk/webhook-audience/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/webhook-audience/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/webhook-audience/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/webhook-audience/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/webhook-audience/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/webhook-audience/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/webhook-audience/src/SeedApi/SeedApi.csproj index b326f82f7432..cda725565abb 100644 --- a/seed/csharp-sdk/webhook-audience/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/webhook-audience/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/webhook-audience/fern + https://github.com/webhook-audience/fern + git true diff --git a/seed/csharp-sdk/webhooks/src/SeedWebhooks.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/webhooks/src/SeedWebhooks.Test/Utils/OptionalComparer.cs index 794573882244..9130e6ae3397 100644 --- a/seed/csharp-sdk/webhooks/src/SeedWebhooks.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/webhooks/src/SeedWebhooks.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/Extensions.cs b/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/Extensions.cs index 13a7c5fab5e7..59059fdaa5ce 100644 --- a/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/Extensions.cs +++ b/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/NullableAttribute.cs b/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/NullableAttribute.cs index 2bb22b45706e..f7aaf948858a 100644 --- a/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedWebhooks.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedWebhooks.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/Optional.cs b/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/Optional.cs index 492184365d16..cee551fa9d65 100644 --- a/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/Optional.cs +++ b/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/OptionalAttribute.cs b/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/OptionalAttribute.cs index 1449ff565f5f..9f7f9434e671 100644 --- a/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedWebhooks.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/QueryStringBuilder.cs b/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/QueryStringBuilder.cs index a27413b888bc..7f0974e9eead 100644 --- a/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/webhooks/src/SeedWebhooks/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/webhooks/src/SeedWebhooks/SeedWebhooks.csproj b/seed/csharp-sdk/webhooks/src/SeedWebhooks/SeedWebhooks.csproj index b25891f528c2..d9b56d60a7b8 100644 --- a/seed/csharp-sdk/webhooks/src/SeedWebhooks/SeedWebhooks.csproj +++ b/seed/csharp-sdk/webhooks/src/SeedWebhooks/SeedWebhooks.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/webhooks/fern + https://github.com/webhooks/fern + git true diff --git a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth.Test/Utils/OptionalComparer.cs index 907b18d4450e..aed1aa465bc1 100644 --- a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/Extensions.cs b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/Extensions.cs index 119b8b865888..0f1dc879aa9b 100644 --- a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/Extensions.cs +++ b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/NullableAttribute.cs index 9e3783b89f30..7b47da944dcc 100644 --- a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedWebsocketBearerAuth.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedWebsocketBearerAuth.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/Optional.cs b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/Optional.cs index 630e4f98b077..5593433b92ab 100644 --- a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/Optional.cs +++ b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/OptionalAttribute.cs index 682a8271d1cb..0230398f6baf 100644 --- a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedWebsocketBearerAuth.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/QueryStringBuilder.cs index af1f434ebb11..14d6fdf91b28 100644 --- a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/SeedWebsocketBearerAuth.csproj b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/SeedWebsocketBearerAuth.csproj index beafc87df977..a316ca4e173c 100644 --- a/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/SeedWebsocketBearerAuth.csproj +++ b/seed/csharp-sdk/websocket-bearer-auth/src/SeedWebsocketBearerAuth/SeedWebsocketBearerAuth.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/websocket-bearer-auth/fern + https://github.com/websocket-bearer-auth/fern + git true diff --git a/seed/csharp-sdk/websocket-inferred-auth/README.md b/seed/csharp-sdk/websocket-inferred-auth/README.md index ed78d3ab23a5..f9ddc85acf68 100644 --- a/seed/csharp-sdk/websocket-inferred-auth/README.md +++ b/seed/csharp-sdk/websocket-inferred-auth/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -111,7 +114,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -124,7 +127,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Auth.GetTokenWithClientCredentialsAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -154,7 +157,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Auth.GetTokenWithClientCredentialsAsync(...); +var parsedData = await client.Auth.GetTokenWithClientCredentialsAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth.Test/Utils/OptionalComparer.cs index b44e9a3228a3..0990dc2ea9f8 100644 --- a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/Extensions.cs b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/Extensions.cs index dfdf20cb78a3..a61f86168186 100644 --- a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/Extensions.cs +++ b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/NullableAttribute.cs index 72fec9d58dcb..a8265d66cb17 100644 --- a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedWebsocketAuth.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedWebsocketAuth.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/Optional.cs b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/Optional.cs index afc18f38c7a5..36a140f7a001 100644 --- a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/Optional.cs +++ b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/OptionalAttribute.cs index 39c44a1d71ec..7a99d508ac58 100644 --- a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedWebsocketAuth.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/QueryStringBuilder.cs index 5201fef7c0b9..d084e414df05 100644 --- a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/SeedWebsocketAuth.csproj b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/SeedWebsocketAuth.csproj index 1f41ebee1659..666019099390 100644 --- a/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/SeedWebsocketAuth.csproj +++ b/seed/csharp-sdk/websocket-inferred-auth/src/SeedWebsocketAuth/SeedWebsocketAuth.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/websocket-inferred-auth/fern + https://github.com/websocket-inferred-auth/fern + git true diff --git a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl.Test/Utils/OptionalComparer.cs index b8f324e92a0d..591b6dcd0154 100644 --- a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/Extensions.cs b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/Extensions.cs index 68b35a35ff53..ecfb000200ce 100644 --- a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/Extensions.cs +++ b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/NullableAttribute.cs b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/NullableAttribute.cs index 670ca77a3de9..47b5c7c075ab 100644 --- a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedWebsocketMultiUrl.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedWebsocketMultiUrl.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/Optional.cs b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/Optional.cs index e35fda0592bc..e09b8a84b3ab 100644 --- a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/Optional.cs +++ b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/OptionalAttribute.cs b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/OptionalAttribute.cs index 04c8715ea30c..69bee6691832 100644 --- a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedWebsocketMultiUrl.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/QueryStringBuilder.cs b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/QueryStringBuilder.cs index 5fd905832a7e..e6f9e5445268 100644 --- a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/WebSockets/Query.cs b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/WebSockets/Query.cs index c4603ab9ca65..f6ffa4889732 100644 --- a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/WebSockets/Query.cs +++ b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/WebSockets/Query.cs @@ -122,7 +122,7 @@ public void Add(string key, Object? value) /// /// Converts the query parameters to a URL-encoded query string. /// - /// A string representation of the query parameters in the format "key1=value1&key2=value2". + /// A string representation of the query parameters in the format "key1=value1&key2=value2". public override string ToString() { return string.Join( diff --git a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/WebSockets/WebSocketClient.cs b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/WebSockets/WebSocketClient.cs index 4f66055b014a..88e1b53dea66 100644 --- a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/WebSockets/WebSocketClient.cs +++ b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/Core/WebSockets/WebSocketClient.cs @@ -134,6 +134,7 @@ private void EnsureConnected() /// Sends a text message instantly through the WebSocket connection. /// /// The text message to send. + /// Token to cancel the send operation. /// A task representing the asynchronous send operation. /// Thrown when the connection is not in Connected status. public global::System.Threading.Tasks.Task SendInstant( @@ -149,6 +150,7 @@ private void EnsureConnected() /// Sends a binary message instantly through the WebSocket connection. /// /// The binary message to send as a Memory<byte>. + /// Token to cancel the send operation. /// A task representing the asynchronous send operation. /// Thrown when the connection is not in Connected status. public global::System.Threading.Tasks.Task SendInstant( @@ -164,6 +166,7 @@ private void EnsureConnected() /// Sends a binary message instantly through the WebSocket connection. /// /// The binary message to send as an ArraySegment<byte>. + /// Token to cancel the send operation. /// A task representing the asynchronous send operation. /// Thrown when the connection is not in Connected status. public global::System.Threading.Tasks.Task SendInstant( @@ -179,6 +182,7 @@ private void EnsureConnected() /// Sends a binary message instantly through the WebSocket connection. /// /// The binary message to send as a byte array. + /// Token to cancel the send operation. /// A task representing the asynchronous send operation. /// Thrown when the connection is not in Connected status. public global::System.Threading.Tasks.Task SendInstant( diff --git a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/SeedWebsocketMultiUrl.csproj b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/SeedWebsocketMultiUrl.csproj index ea748afb231d..94ce248789f9 100644 --- a/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/SeedWebsocketMultiUrl.csproj +++ b/seed/csharp-sdk/websocket-multi-url/no-custom-config/src/SeedWebsocketMultiUrl/SeedWebsocketMultiUrl.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/websocket-multi-url/fern + https://github.com/websocket-multi-url/fern + git true diff --git a/seed/csharp-sdk/websocket/no-custom-config/README.md b/seed/csharp-sdk/websocket/no-custom-config/README.md index 9ae48d8da0c9..e5eb1489c2c0 100644 --- a/seed/csharp-sdk/websocket/no-custom-config/README.md +++ b/seed/csharp-sdk/websocket/no-custom-config/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Status.GetStatusAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Status.GetStatusAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Status.GetStatusAsync(...); +var parsedData = await client.Status.GetStatusAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket.Test/Utils/OptionalComparer.cs index 1fb11a0355ed..70293a63a60a 100644 --- a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/Extensions.cs b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/Extensions.cs index 756e87ed53ab..77a014b05cde 100644 --- a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/Extensions.cs +++ b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/NullableAttribute.cs b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/NullableAttribute.cs index 09fe857cf2dd..1966e565af50 100644 --- a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedWebsocket.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedWebsocket.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/Optional.cs b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/Optional.cs index b637adbe0aad..4276559a732e 100644 --- a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/Optional.cs +++ b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/OptionalAttribute.cs b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/OptionalAttribute.cs index 52d7d3a4f85f..fb7f5c792125 100644 --- a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedWebsocket.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/QueryStringBuilder.cs b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/QueryStringBuilder.cs index c2f1ec8fd9db..86e6d9c3fcbc 100644 --- a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/SeedWebsocket.csproj b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/SeedWebsocket.csproj index 9e88ae054f45..c5eb11dbfe51 100644 --- a/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/SeedWebsocket.csproj +++ b/seed/csharp-sdk/websocket/no-custom-config/src/SeedWebsocket/SeedWebsocket.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/websocket/fern + https://github.com/websocket/fern + git true diff --git a/seed/csharp-sdk/websocket/with-websockets/README.md b/seed/csharp-sdk/websocket/with-websockets/README.md index 9ae48d8da0c9..e5eb1489c2c0 100644 --- a/seed/csharp-sdk/websocket/with-websockets/README.md +++ b/seed/csharp-sdk/websocket/with-websockets/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Status.GetStatusAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Status.GetStatusAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Status.GetStatusAsync(...); +var parsedData = await client.Status.GetStatusAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket.Test/Utils/OptionalComparer.cs index 1fb11a0355ed..70293a63a60a 100644 --- a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/Extensions.cs b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/Extensions.cs index 756e87ed53ab..77a014b05cde 100644 --- a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/Extensions.cs +++ b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/NullableAttribute.cs b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/NullableAttribute.cs index 09fe857cf2dd..1966e565af50 100644 --- a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedWebsocket.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedWebsocket.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/Optional.cs b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/Optional.cs index b637adbe0aad..4276559a732e 100644 --- a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/Optional.cs +++ b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/OptionalAttribute.cs b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/OptionalAttribute.cs index 52d7d3a4f85f..fb7f5c792125 100644 --- a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedWebsocket.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/QueryStringBuilder.cs b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/QueryStringBuilder.cs index c2f1ec8fd9db..86e6d9c3fcbc 100644 --- a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/WebSockets/Query.cs b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/WebSockets/Query.cs index 0cf96cf46bca..7085dec15f95 100644 --- a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/WebSockets/Query.cs +++ b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/WebSockets/Query.cs @@ -122,7 +122,7 @@ public void Add(string key, Object? value) /// /// Converts the query parameters to a URL-encoded query string. /// - /// A string representation of the query parameters in the format "key1=value1&key2=value2". + /// A string representation of the query parameters in the format "key1=value1&key2=value2". public override string ToString() { return string.Join( diff --git a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/WebSockets/WebSocketClient.cs b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/WebSockets/WebSocketClient.cs index f59c4aebcceb..11abf654aa8e 100644 --- a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/WebSockets/WebSocketClient.cs +++ b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/Core/WebSockets/WebSocketClient.cs @@ -134,6 +134,7 @@ private void EnsureConnected() /// Sends a text message instantly through the WebSocket connection. /// /// The text message to send. + /// Token to cancel the send operation. /// A task representing the asynchronous send operation. /// Thrown when the connection is not in Connected status. public global::System.Threading.Tasks.Task SendInstant( @@ -149,6 +150,7 @@ private void EnsureConnected() /// Sends a binary message instantly through the WebSocket connection. /// /// The binary message to send as a Memory<byte>. + /// Token to cancel the send operation. /// A task representing the asynchronous send operation. /// Thrown when the connection is not in Connected status. public global::System.Threading.Tasks.Task SendInstant( @@ -164,6 +166,7 @@ private void EnsureConnected() /// Sends a binary message instantly through the WebSocket connection. /// /// The binary message to send as an ArraySegment<byte>. + /// Token to cancel the send operation. /// A task representing the asynchronous send operation. /// Thrown when the connection is not in Connected status. public global::System.Threading.Tasks.Task SendInstant( @@ -179,6 +182,7 @@ private void EnsureConnected() /// Sends a binary message instantly through the WebSocket connection. /// /// The binary message to send as a byte array. + /// Token to cancel the send operation. /// A task representing the asynchronous send operation. /// Thrown when the connection is not in Connected status. public global::System.Threading.Tasks.Task SendInstant( diff --git a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/SeedWebsocket.csproj b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/SeedWebsocket.csproj index 6983a8382ab1..3a04d989478e 100644 --- a/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/SeedWebsocket.csproj +++ b/seed/csharp-sdk/websocket/with-websockets/src/SeedWebsocket/SeedWebsocket.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/websocket/fern + https://github.com/websocket/fern + git true diff --git a/seed/csharp-sdk/x-fern-default/README.md b/seed/csharp-sdk/x-fern-default/README.md index 5a413f992b6e..3ca56d349586 100644 --- a/seed/csharp-sdk/x-fern-default/README.md +++ b/seed/csharp-sdk/x-fern-default/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -42,7 +45,7 @@ Instantiate and use the client with the following: ```csharp using SeedApi; -var client = new SeedApiClient("API_VERSION"); +var client = new SeedApiClient("2024-02-08"); await client.TestGetAsync(new TestGetRequest { Region = "region" }); ``` @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.TestGetAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.TestGetAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.TestGetAsync(...); +var parsedData = await client.TestGetAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/x-fern-default/snippet.json b/seed/csharp-sdk/x-fern-default/snippet.json index b2af146163cb..5797cb21d931 100644 --- a/seed/csharp-sdk/x-fern-default/snippet.json +++ b/seed/csharp-sdk/x-fern-default/snippet.json @@ -10,7 +10,7 @@ }, "snippet": { "type": "csharp", - "client": "using SeedApi;\n\nvar client = new SeedApiClient(\"API_VERSION\");\nawait client.TestGetAsync(new TestGetRequest { Region = \"region\" });\n" + "client": "using SeedApi;\n\nvar client = new SeedApiClient(\"2024-02-08\");\nawait client.TestGetAsync(new TestGetRequest { Region = \"region\" });\n" } } ] diff --git a/seed/csharp-sdk/x-fern-default/src/SeedApi.Test/Unit/MockServer/BaseMockServerTest.cs b/seed/csharp-sdk/x-fern-default/src/SeedApi.Test/Unit/MockServer/BaseMockServerTest.cs index 1356ee7d0bd9..001f637901d6 100644 --- a/seed/csharp-sdk/x-fern-default/src/SeedApi.Test/Unit/MockServer/BaseMockServerTest.cs +++ b/seed/csharp-sdk/x-fern-default/src/SeedApi.Test/Unit/MockServer/BaseMockServerTest.cs @@ -24,7 +24,7 @@ public void GlobalSetup() // Initialize the Client Client = new SeedApiClient( - "API_VERSION", + "2024-02-08", clientOptions: new ClientOptions { BaseUrl = Server.Urls[0], MaxRetries = 0 } ); } diff --git a/seed/csharp-sdk/x-fern-default/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/x-fern-default/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/x-fern-default/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/x-fern-default/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/x-fern-default/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/x-fern-default/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/x-fern-default/src/SeedApi/SeedApi.csproj index 7a7e47f03e0e..f88b8177d0c7 100644 --- a/seed/csharp-sdk/x-fern-default/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/x-fern-default/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/x-fern-default/fern + https://github.com/x-fern-default/fern + git true diff --git a/seed/csharp-sdk/x-fern-global-parameters/README.md b/seed/csharp-sdk/x-fern-global-parameters/README.md index fc77d90796c0..3987eb032023 100644 --- a/seed/csharp-sdk/x-fern-global-parameters/README.md +++ b/seed/csharp-sdk/x-fern-global-parameters/README.md @@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#. ## Requirements This SDK requires: +- .NET 8 and above +- .NET Framework 4.6.2 and above +- .NET Standard 2.0 and above ## Installation @@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior. var response = await client.Products.SearchAsync( ..., new RequestOptions { - MaxRetries: 0 // Override MaxRetries at the request level + MaxRetries = 0 // Override MaxRetries at the request level } ); ``` @@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t var response = await client.Products.SearchAsync( ..., new RequestOptions { - Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s + Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s } ); ``` @@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId)) } // For the default behavior, simply await without .WithRawResponse() -var data = await client.Products.SearchAsync(...); +var parsedData = await client.Products.SearchAsync(...); // .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse) // and on endpoints with no response body (returns RawResponse only). diff --git a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi.Test/Utils/OptionalComparer.cs index 98bfcac477b8..f816065d36e0 100644 --- a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi.Test/Utils/OptionalComparer.cs +++ b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi.Test/Utils/OptionalComparer.cs @@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra /// /// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer. - /// This enables recursive comparison of nested OneOf values within Optional types. + /// This enables recursive comparison of nested OneOf values within Optional<T> types. /// private class OneOfEqualityAdapter : EqualityAdapter { diff --git a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/Extensions.cs index 7338b20e748c..ed17f99952fb 100644 --- a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/Extensions.cs +++ b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/Extensions.cs @@ -20,6 +20,7 @@ public static string Stringify(this Enum value) /// /// Asserts that a condition is true, throwing an exception with the specified message if it is false. /// + /// The object the extension method is invoked on; unused. /// The condition to assert. /// The exception message if the assertion fails. /// Thrown when the condition is false. @@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message) /// Asserts that a value is not null, throwing an exception with the specified message if it is null. /// /// The type of the value to assert. + /// The object the extension method is invoked on; unused. /// The value to assert is not null. /// The exception message if the assertion fails. /// The non-null value. diff --git a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/NullableAttribute.cs index a1d30328bf9a..8e57fe6e0d1b 100644 --- a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/NullableAttribute.cs +++ b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/NullableAttribute.cs @@ -2,7 +2,7 @@ namespace SeedApi.Core; /// /// Marks a property as nullable in the OpenAPI specification. -/// When applied to Optional properties, this indicates that null values should be +/// When applied to Optional<T> properties, this indicates that null values should be /// written to JSON when the optional is defined with null. /// /// @@ -10,9 +10,9 @@ namespace SeedApi.Core; /// - Without [Nullable]: null values are invalid (omit from JSON at runtime) /// - With [Nullable]: null values are written to JSON /// -/// For Optional properties (also marked with [Optional]): -/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case) -/// - With [Nullable]: Optional.Of(null) → write null to JSON +/// For Optional<T> properties (also marked with [Optional]): +/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case) +/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class NullableAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/Optional.cs index d174943cb2cf..2efc4945ec72 100644 --- a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/Optional.cs +++ b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/Optional.cs @@ -263,7 +263,7 @@ public override int GetHashCode() } /// -/// Extension methods for Optional to simplify common operations. +/// Extension methods for Optional<T> to simplify common operations. /// public static class OptionalExtensions { @@ -341,7 +341,7 @@ Func mapper /// Adds a nullable value to a dictionary only if it is not null. /// This is useful for regular nullable properties where null means "omit from request". /// - /// The type of the value (must be a reference type or Nullable). + /// The type of the value (must be a reference type or Nullable<T>). /// The nullable value to add. /// The dictionary to add to. /// The key to use in the dictionary. @@ -395,7 +395,7 @@ string key } /// -/// JSON converter factory for Optional that handles undefined vs null correctly. +/// JSON converter factory for Optional<T> that handles undefined vs null correctly. /// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined. /// public class OptionalJsonConverterFactory : JsonConverterFactory @@ -420,7 +420,7 @@ JsonSerializerOptions options } /// -/// JSON converter for Optional that unwraps the value during serialization. +/// JSON converter for Optional<T> that unwraps the value during serialization. /// The actual property skipping is handled by the OptionalTypeInfoResolver. /// public class OptionalJsonConverter : JsonConverter> diff --git a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/OptionalAttribute.cs index 4c4c4073a0ae..543e999e42d6 100644 --- a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/OptionalAttribute.cs +++ b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/OptionalAttribute.cs @@ -2,16 +2,16 @@ namespace SeedApi.Core; /// /// Marks a property as optional in the OpenAPI specification. -/// Optional properties use the Optional type and can be undefined (not present in JSON). +/// Optional properties use the Optional<T> type and can be undefined (not present in JSON). /// /// -/// Properties marked with [Optional] should use the Optional type: -/// - Undefined: Optional.Undefined → omitted from JSON -/// - Defined: Optional.Of(value) → written to JSON +/// Properties marked with [Optional] should use the Optional<T> type: +/// - Undefined: Optional<T>.Undefined → omitted from JSON +/// - Defined: Optional<T>.Of(value) → written to JSON /// /// Combine with [Nullable] to allow null values: -/// - [Optional, Nullable] Optional → can be undefined, null, or a value -/// - [Optional] Optional → can be undefined or a value (null is invalid) +/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value +/// - [Optional] Optional<string> → can be undefined or a value (null is invalid) /// [global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)] public class OptionalAttribute : global::System.Attribute { } diff --git a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/QueryStringBuilder.cs index 2a7255f9993a..04ecc2efa5e3 100644 --- a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/QueryStringBuilder.cs +++ b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/Core/QueryStringBuilder.cs @@ -119,10 +119,10 @@ public static string EncodePathSegment(string value) #endif } +#if NET6_0_OR_GREATER /// /// Builds a query string from the provided parameters. /// -#if NET6_0_OR_GREATER public static string Build(ReadOnlySpan> parameters) { if (parameters.IsEmpty) diff --git a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/SeedApi.csproj index 3564a73f5aca..1ef0b0e3ef8f 100644 --- a/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/SeedApi.csproj +++ b/seed/csharp-sdk/x-fern-global-parameters/src/SeedApi/SeedApi.csproj @@ -8,7 +8,11 @@ $(Version) $(Version) README.md + true + $(NoWarn);CS1591 https://github.com/x-fern-global-parameters/fern + https://github.com/x-fern-global-parameters/fern + git true diff --git a/test-definitions/fern/apis/csharp-xml-entities/definition/__package__.yml b/test-definitions/fern/apis/csharp-xml-entities/definition/__package__.yml index a73f9dce8933..fe971672093b 100644 --- a/test-definitions/fern/apis/csharp-xml-entities/definition/__package__.yml +++ b/test-definitions/fern/apis/csharp-xml-entities/definition/__package__.yml @@ -16,6 +16,12 @@ types: specialChars: type: optional docs: "Special characters:   … · ©" + documentationLink: + type: optional + docs: 'See see here for details' + escapedDocumentationLink: + type: optional + docs: 'See see here for details' service: auth: false diff --git a/test-definitions/fern/apis/csharp-xml-entities/openapi.yml b/test-definitions/fern/apis/csharp-xml-entities/openapi.yml index 8bba489a663c..63cce044d070 100644 --- a/test-definitions/fern/apis/csharp-xml-entities/openapi.yml +++ b/test-definitions/fern/apis/csharp-xml-entities/openapi.yml @@ -39,6 +39,14 @@ components: type: string nullable: true description: "Special characters:   … · ©" + documentationLink: + type: string + nullable: true + description: 'See see here for details' + escapedDocumentationLink: + type: string + nullable: true + description: 'See see here for details' required: - timeZoneOffset - mathExpression From df5db961ecbb170e18ae678ae50ef7d9a3c01f41 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 20 Aug 2026 13:49:31 +0000 Subject: [PATCH 2/7] chore(csharp): release 2.83.0 --- .../feat-docs-and-package-metadata.yml | 0 .../fix-client-options-global-headers.yml | 0 .../fix-doc-comment-attribute-escaping.yml | 0 .../fix-readme-requirements.yml | 0 .../fix-readme-snippets.yml | 0 .../fix-union-cref-doc-comments.yml | 0 .../fix-xml-doc-comments.yml | 0 generators/csharp/sdk/versions.yml | 69 +++++++++++++++++++ 8 files changed, 69 insertions(+) rename generators/csharp/sdk/changes/{unreleased => 2.83.0}/feat-docs-and-package-metadata.yml (100%) rename generators/csharp/sdk/changes/{unreleased => 2.83.0}/fix-client-options-global-headers.yml (100%) rename generators/csharp/sdk/changes/{unreleased => 2.83.0}/fix-doc-comment-attribute-escaping.yml (100%) rename generators/csharp/sdk/changes/{unreleased => 2.83.0}/fix-readme-requirements.yml (100%) rename generators/csharp/sdk/changes/{unreleased => 2.83.0}/fix-readme-snippets.yml (100%) rename generators/csharp/sdk/changes/{unreleased => 2.83.0}/fix-union-cref-doc-comments.yml (100%) rename generators/csharp/sdk/changes/{unreleased => 2.83.0}/fix-xml-doc-comments.yml (100%) diff --git a/generators/csharp/sdk/changes/unreleased/feat-docs-and-package-metadata.yml b/generators/csharp/sdk/changes/2.83.0/feat-docs-and-package-metadata.yml similarity index 100% rename from generators/csharp/sdk/changes/unreleased/feat-docs-and-package-metadata.yml rename to generators/csharp/sdk/changes/2.83.0/feat-docs-and-package-metadata.yml diff --git a/generators/csharp/sdk/changes/unreleased/fix-client-options-global-headers.yml b/generators/csharp/sdk/changes/2.83.0/fix-client-options-global-headers.yml similarity index 100% rename from generators/csharp/sdk/changes/unreleased/fix-client-options-global-headers.yml rename to generators/csharp/sdk/changes/2.83.0/fix-client-options-global-headers.yml diff --git a/generators/csharp/sdk/changes/unreleased/fix-doc-comment-attribute-escaping.yml b/generators/csharp/sdk/changes/2.83.0/fix-doc-comment-attribute-escaping.yml similarity index 100% rename from generators/csharp/sdk/changes/unreleased/fix-doc-comment-attribute-escaping.yml rename to generators/csharp/sdk/changes/2.83.0/fix-doc-comment-attribute-escaping.yml diff --git a/generators/csharp/sdk/changes/unreleased/fix-readme-requirements.yml b/generators/csharp/sdk/changes/2.83.0/fix-readme-requirements.yml similarity index 100% rename from generators/csharp/sdk/changes/unreleased/fix-readme-requirements.yml rename to generators/csharp/sdk/changes/2.83.0/fix-readme-requirements.yml diff --git a/generators/csharp/sdk/changes/unreleased/fix-readme-snippets.yml b/generators/csharp/sdk/changes/2.83.0/fix-readme-snippets.yml similarity index 100% rename from generators/csharp/sdk/changes/unreleased/fix-readme-snippets.yml rename to generators/csharp/sdk/changes/2.83.0/fix-readme-snippets.yml diff --git a/generators/csharp/sdk/changes/unreleased/fix-union-cref-doc-comments.yml b/generators/csharp/sdk/changes/2.83.0/fix-union-cref-doc-comments.yml similarity index 100% rename from generators/csharp/sdk/changes/unreleased/fix-union-cref-doc-comments.yml rename to generators/csharp/sdk/changes/2.83.0/fix-union-cref-doc-comments.yml diff --git a/generators/csharp/sdk/changes/unreleased/fix-xml-doc-comments.yml b/generators/csharp/sdk/changes/2.83.0/fix-xml-doc-comments.yml similarity index 100% rename from generators/csharp/sdk/changes/unreleased/fix-xml-doc-comments.yml rename to generators/csharp/sdk/changes/2.83.0/fix-xml-doc-comments.yml diff --git a/generators/csharp/sdk/versions.yml b/generators/csharp/sdk/versions.yml index e3c8aa67c069..2ee007ab8217 100644 --- a/generators/csharp/sdk/versions.yml +++ b/generators/csharp/sdk/versions.yml @@ -1,4 +1,73 @@ # yaml-language-server: $schema=../../../fern-versions-yml.schema.json +- version: 2.83.0 + changelogEntry: + - summary: | + Added a `generate-documentation-file` config option (default `true`) so the + generated csproj emits XML documentation and the published NuGet package ships + `lib//.xml`, giving consumers IntelliSense. CS1591 is + suppressed so enabling documentation does not introduce warnings for + undocumented members. + type: feat + - summary: | + Added a `package-metadata` config block for NuGet metadata written into the + generated csproj: `description`, `authors`, `tags`, `copyright`, `icon`, + `project-url`, `repository-url`, `repository-type`, `include-source-link` + (adds `Microsoft.SourceLink.GitHub`) and `include-symbols` (produces a + `.snupkg`). + type: feat + - summary: | + Global header values set on `ClientOptions` are now respected in the default + (non-unified) client shape. Previously the generated root client read only the + constructor parameter for a promoted global header, so + `new Client(clientOptions: new ClientOptions { Version = "..." })` was silently + ignored and a stray environment variable could win instead. The resolution + order is now: explicit constructor argument, `ClientOptions` property, + environment variable, then the literal/client default. + type: fix + - summary: | + `ClientOptions.Clone()` now copies literal global header properties (e.g. + `Version`), which were previously dropped when the options were cloned. + type: fix + - summary: | + Escape markup characters in the attribute values of documentation comment tags. Descriptions + containing links such as `` no longer emit invalid + XML (CS1570) in generated documentation comments, while attribute values that already contain + character or entity references are left untouched. + type: fix + - summary: | + The generated README's `## Requirements` section is now populated with the + project's target frameworks (".NET 8 and above", ".NET Framework 4.6.2 and + above", ".NET Standard 2.0 and above"). Previously the C# generator passed an + empty requirements list, so the section rendered as a dangling + "This SDK requires:" with no entries. + type: fix + - summary: | + README and dynamic snippets no longer pass an upper-cased placeholder for + global header constructor parameters (e.g. `new Client("TOKEN", "VERSION")`, + which sent the literal header value `VERSION` at runtime). Snippets now use + the header's literal or client default value when one is known. + type: fix + - summary: | + Fixed invalid C# in the generated README: `RequestOptions` examples used + object-initializer syntax with `:` instead of `=` (`new RequestOptions { MaxRetries: 0 }`), + and the `WithRawResponse` section declared `var data` twice in one block. + type: fix + - summary: | + Fix invalid `` documentation comments generated for union types. Type names + are now converted to documentation comment identifiers (`List` becomes + `List{String}`, `object?` becomes `object`), and types that cannot be expressed as an + identifier (arrays, nested generic arguments) are rendered as escaped inline code instead. + This removes CS1570/CS1584/CS1658 warnings from generated SDKs that contain unions when XML + documentation is enabled. + type: fix + - summary: | + Escaped generic type syntax in the XML doc comments of the generated core + files (`Optional`, `OptionalAttribute`, `NullableAttribute`, `Extensions`), + and added the missing `param` tags on `Extensions.Assert`. Building generated + SDKs with XML documentation enabled no longer emits CS1570/CS1573 warnings. + type: fix + createdAt: "2026-08-20" + irVersion: 67 - version: 2.82.1 changelogEntry: - summary: | From c2c69d7cf16848609d7cf4551372080a851157b0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 20 Aug 2026 13:50:00 +0000 Subject: [PATCH 3/7] chore(generator-cli): release 0.9.55 --- .../fix-empty-readme-requirements.yml | 0 packages/generator-cli/versions.yml | 8 ++++++++ 2 files changed, 8 insertions(+) rename packages/generator-cli/changes/{unreleased => 0.9.55}/fix-empty-readme-requirements.yml (100%) diff --git a/packages/generator-cli/changes/unreleased/fix-empty-readme-requirements.yml b/packages/generator-cli/changes/0.9.55/fix-empty-readme-requirements.yml similarity index 100% rename from packages/generator-cli/changes/unreleased/fix-empty-readme-requirements.yml rename to packages/generator-cli/changes/0.9.55/fix-empty-readme-requirements.yml diff --git a/packages/generator-cli/versions.yml b/packages/generator-cli/versions.yml index e3bac177f4ba..d5235b91fc1f 100644 --- a/packages/generator-cli/versions.yml +++ b/packages/generator-cli/versions.yml @@ -1,4 +1,12 @@ # yaml-language-server: $schema=../../versions-yml.schema.json +- version: 0.9.55 + changelogEntry: + - summary: | + The README's `## Requirements` section is now omitted when the generator + supplies an empty requirements list, instead of rendering a heading followed by + a dangling "This SDK requires:" line. + type: fix + createdAt: "2026-08-20" - version: 0.9.54 changelogEntry: - summary: | From b94294427aa42c087708c5cdeea655189234958a Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2026 10:41:52 -0400 Subject: [PATCH 4/7] fix(go): generate valid README snippets for auth options, errors.As, and pagination (#17465) * fix(go): generate valid README snippets for auth options, errors.As, and pagination Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(go): respect omitted basic-auth credentials and avoid redeclared variables in pagination README snippet Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * chore: retrigger CI Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * chore: retrigger CI Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(go): only emit README Pagination section for generated paginated endpoints Co-Authored-By: bot_apk * chore: clarify go readme pagination changelog entry Co-Authored-By: bot_apk --------- Co-authored-by: adi.david Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: bot_apk --- .../sdk/src/readme/ReadmeConfigBuilder.ts | 2 + .../sdk/src/readme/ReadmeSnippetBuilder.ts | 182 ++++++++++++++++-- .../unreleased/fix-readme-snippets.yml | 18 ++ seed/go-sdk/accept-header/README.md | 2 +- seed/go-sdk/alias-extends/README.md | 5 +- seed/go-sdk/alias/README.md | 5 +- seed/go-sdk/allof-inline/README.md | 5 +- seed/go-sdk/allof/README.md | 5 +- seed/go-sdk/any-auth/README.md | 15 +- .../api-wide-base-path-with-default/README.md | 5 +- seed/go-sdk/api-wide-base-path/README.md | 5 +- seed/go-sdk/audiences/README.md | 5 +- .../README.md | 12 +- .../wire-tests/README.md | 6 +- seed/go-sdk/basic-auth/README.md | 6 +- .../README.md | 11 +- seed/go-sdk/bytes-download/README.md | 5 +- seed/go-sdk/bytes-upload/README.md | 5 +- seed/go-sdk/client-side-params/README.md | 2 +- seed/go-sdk/content-type/README.md | 5 +- .../go-sdk/cross-package-type-names/README.md | 5 +- .../README.md | 5 +- seed/go-sdk/endpoint-security-auth/README.md | 15 +- seed/go-sdk/enum/README.md | 5 +- seed/go-sdk/error-property/README.md | 5 +- seed/go-sdk/errors/README.md | 5 +- .../always-send-required-properties/README.md | 2 +- .../README.md | 2 +- seed/go-sdk/examples/client-name/README.md | 2 +- .../export-all-requests-at-root/README.md | 2 +- .../examples/exported-client-name/README.md | 2 +- .../examples/getters-pass-by-value/README.md | 2 +- .../examples/no-custom-config/README.md | 2 +- seed/go-sdk/examples/package-path/README.md | 2 +- seed/go-sdk/examples/readme-config/README.md | 2 +- seed/go-sdk/examples/v0/README.md | 2 +- .../exhaustive/no-custom-config/README.md | 68 ++++++- .../omit-empty-request-wrappers/README.md | 68 ++++++- seed/go-sdk/extends/README.md | 5 +- seed/go-sdk/extra-properties/README.md | 5 +- seed/go-sdk/file-download/README.md | 5 +- seed/go-sdk/file-upload-openapi/README.md | 5 +- .../file-upload/no-custom-config/README.md | 5 +- .../go-sdk/file-upload/package-name/README.md | 5 +- seed/go-sdk/file-upload/v0/README.md | 5 +- seed/go-sdk/folders/README.md | 5 +- seed/go-sdk/go-content-type/README.md | 2 +- seed/go-sdk/go-date-containers/README.md | 5 +- .../go-deterministic-ordering/README.md | 68 ++++++- .../no-custom-config/README.md | 5 +- seed/go-sdk/go-nullable-date-ref/README.md | 5 +- seed/go-sdk/go-nullable-wire-tests/README.md | 5 +- .../no-custom-config/README.md | 6 +- .../no-custom-config/README.md | 6 +- seed/go-sdk/go-optional-header-env/README.md | 11 +- .../go-optional-literal-alias/README.md | 5 +- .../no-custom-config/README.md | 5 +- .../respect-optional-request-body/README.md | 5 +- .../go-pagination-offset-item-index/README.md | 8 +- .../go-request-body-pagination/README.md | 8 +- .../README.md | 2 +- .../dedupe-union-base-properties/README.md | 5 +- .../no-custom-config/README.md | 5 +- .../README.md | 11 +- seed/go-sdk/header-auth/README.md | 6 +- seed/go-sdk/http-head/README.md | 5 +- seed/go-sdk/idempotency-headers/README.md | 2 +- .../auto-generate-idempotency-key/README.md | 2 +- .../imdb/allow-user-agent-app-info/README.md | 2 +- seed/go-sdk/imdb/deep-package-path/README.md | 2 +- .../README.md | 2 +- .../imdb/include-platform-headers/README.md | 2 +- seed/go-sdk/imdb/no-custom-config/README.md | 2 +- seed/go-sdk/imdb/omit-fern-headers/README.md | 2 +- seed/go-sdk/imdb/package-path/README.md | 2 +- .../go-sdk/imdb/with-wiremock-tests/README.md | 2 +- seed/go-sdk/inferred-auth-explicit/README.md | 5 +- .../inferred-auth-implicit-api-key/README.md | 5 +- .../README.md | 5 +- .../README.md | 5 +- seed/go-sdk/inferred-auth-implicit/README.md | 5 +- .../inline-enum-type-name-override/README.md | 5 +- seed/go-sdk/license/README.md | 5 +- seed/go-sdk/literal-user-agent/README.md | 5 +- seed/go-sdk/literal/README.md | 5 +- .../mixed-case/default-values/README.md | 5 +- .../mixed-case/no-custom-config/README.md | 5 +- seed/go-sdk/mixed-file-directory/README.md | 5 +- .../multi-content-type-examples/README.md | 5 +- seed/go-sdk/multi-line-docs/README.md | 5 +- .../README.md | 2 +- .../multi-url-environment-reference/README.md | 2 +- seed/go-sdk/multi-url-environment/README.md | 2 +- seed/go-sdk/multiple-request-bodies/README.md | 2 +- seed/go-sdk/no-content-response/README.md | 5 +- seed/go-sdk/no-environment/README.md | 2 +- seed/go-sdk/no-retries/README.md | 5 +- seed/go-sdk/null-type/README.md | 5 +- seed/go-sdk/nullable-allof-extends/README.md | 5 +- seed/go-sdk/nullable-optional/README.md | 5 +- .../dynamic-snippets-disabled/README.md | 5 +- seed/go-sdk/nullable/README.md | 5 +- .../oauth-client-credentials-custom/README.md | 6 +- .../README.md | 6 +- .../README.md | 12 +- .../no-custom-config/README.md | 6 +- .../README.md | 6 +- .../README.md | 6 +- .../README.md | 6 +- .../README.md | 6 +- .../go-sdk/oauth-client-credentials/README.md | 6 +- seed/go-sdk/oauth-pkce/README.md | 5 +- .../README.md | 5 +- .../no-custom-config/README.md | 5 +- seed/go-sdk/openapi-subtitle/README.md | 5 +- seed/go-sdk/optional/README.md | 5 +- .../package-yml/no-custom-config/README.md | 5 +- seed/go-sdk/pagination-custom/README.md | 69 +------ seed/go-sdk/pagination-uri-path/README.md | 69 +------ seed/go-sdk/pagination/README.md | 7 +- .../no-custom-config/README.md | 5 +- .../path-parameters/package-name/README.md | 5 +- seed/go-sdk/path-parameters/v0/README.md | 5 +- seed/go-sdk/plain-text/README.md | 5 +- seed/go-sdk/property-access/README.md | 5 +- .../query-param-name-conflict/README.md | 5 +- .../README.md | 5 +- .../go-sdk/query-parameters-openapi/README.md | 5 +- seed/go-sdk/query-parameters/README.md | 5 +- seed/go-sdk/required-nullable/README.md | 5 +- seed/go-sdk/reserved-keywords/README.md | 5 +- .../respect-optional-request-body/README.md | 5 +- seed/go-sdk/response-property/README.md | 5 +- .../README.md | 5 +- .../with-wire-tests/README.md | 5 +- .../with-wire-tests/README.md | 5 +- .../server-sent-events-resumable/README.md | 5 +- .../with-wire-tests/README.md | 5 +- .../disable-server-url-variables/README.md | 5 +- .../no-custom-config/README.md | 5 +- .../disable-server-url-variables/README.md | 5 +- .../no-custom-config/README.md | 5 +- seed/go-sdk/simple-api/README.md | 2 +- seed/go-sdk/simple-fhir/README.md | 5 +- .../single-url-environment-default/README.md | 2 +- .../README.md | 2 +- seed/go-sdk/streaming-parameter/README.md | 5 +- seed/go-sdk/streaming/README.md | 5 +- seed/go-sdk/trace/README.md | 2 +- .../README.md | 5 +- .../no-custom-config/README.md | 5 +- .../undiscriminated-unions/v0/README.md | 5 +- seed/go-sdk/union-query-parameters/README.md | 5 +- seed/go-sdk/unions-with-local-date/README.md | 5 +- seed/go-sdk/unions/no-custom-config/README.md | 5 +- seed/go-sdk/unions/package-name/README.md | 5 +- seed/go-sdk/unions/v0/README.md | 5 +- seed/go-sdk/unknown/README.md | 5 +- seed/go-sdk/url-form-encoded/README.md | 5 +- seed/go-sdk/validation/README.md | 5 +- seed/go-sdk/variables/README.md | 5 +- seed/go-sdk/version-no-default/README.md | 5 +- seed/go-sdk/version/README.md | 5 +- seed/go-sdk/websocket-inferred-auth/README.md | 5 +- seed/go-sdk/websocket/README.md | 5 +- .../README.md | 5 +- .../x-fern-default/no-custom-config/README.md | 5 +- .../go-sdk/x-fern-global-parameters/README.md | 5 +- 168 files changed, 746 insertions(+), 572 deletions(-) create mode 100644 generators/go/sdk/changes/unreleased/fix-readme-snippets.yml diff --git a/generators/go-v2/sdk/src/readme/ReadmeConfigBuilder.ts b/generators/go-v2/sdk/src/readme/ReadmeConfigBuilder.ts index 6be0b59b6595..5e7936e9d055 100644 --- a/generators/go-v2/sdk/src/readme/ReadmeConfigBuilder.ts +++ b/generators/go-v2/sdk/src/readme/ReadmeConfigBuilder.ts @@ -22,6 +22,7 @@ export class ReadmeConfigBuilder { endpointSnippets }); const snippetsByFeatureId = readmeSnippetBuilder.buildReadmeSnippetsByFeatureId(); + const addendumsByFeatureId = readmeSnippetBuilder.buildReadmeAddendumsByFeatureId(); const features: FernGeneratorCli.ReadmeFeature[] = []; for (const feature of featureConfig.features) { @@ -35,6 +36,7 @@ export class ReadmeConfigBuilder { id: feature.id, advanced: feature.advanced, description: feature.description, + addendum: addendumsByFeatureId[feature.id] ?? feature.addendum, snippets: snippetsForFeature, snippetsAreOptional: false }); diff --git a/generators/go-v2/sdk/src/readme/ReadmeSnippetBuilder.ts b/generators/go-v2/sdk/src/readme/ReadmeSnippetBuilder.ts index 95812f71424d..f2dbc9d84570 100644 --- a/generators/go-v2/sdk/src/readme/ReadmeSnippetBuilder.ts +++ b/generators/go-v2/sdk/src/readme/ReadmeSnippetBuilder.ts @@ -1,4 +1,5 @@ import { AbstractReadmeSnippetBuilder, GeneratorError } from "@fern-api/base-generator"; +import { assertNever } from "@fern-api/core-utils"; import { FernGeneratorCli } from "@fern-fern/generator-cli-sdk"; import { FernGeneratorExec } from "@fern-fern/generator-exec-sdk"; import { FernIr } from "@fern-fern/ir-sdk"; @@ -90,7 +91,8 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder { ? { [FernGeneratorCli.StructuredFeatureId.Pagination]: { renderer: this.renderPaginationSnippet.bind(this), - predicate: (endpoint: EndpointWithFilepath) => endpoint.endpoint.pagination != null + predicate: (endpoint: EndpointWithFilepath) => + this.context.isEnabledPaginationEndpoint(endpoint.endpoint) } } : undefined) @@ -109,6 +111,73 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder { return snippetsByFeatureId; } + public buildReadmeAddendumsByFeatureId(): Record { + const addendums: Record = {}; + const environmentVariablesAddendum = this.buildEnvironmentVariablesAddendum(); + if (environmentVariablesAddendum != null) { + addendums[FernGeneratorCli.StructuredFeatureId.RequestOptions] = environmentVariablesAddendum; + } + return addendums; + } + + private buildEnvironmentVariablesAddendum(): string | undefined { + const environmentVariables = this.getAuthEnvironmentVariables(); + if (environmentVariables.length === 0) { + return undefined; + } + const bulletedList = environmentVariables + .map((environmentVariable) => `- \`${environmentVariable}\``) + .join("\n"); + return [ + "", + "When credentials are not explicitly provided, the client reads them from the", + "following environment variables:", + "", + bulletedList + ].join("\n"); + } + + private getAuthEnvironmentVariables(): FernIr.EnvironmentVariable[] { + const environmentVariables: FernIr.EnvironmentVariable[] = []; + for (const scheme of this.context.ir.auth?.schemes ?? []) { + switch (scheme.type) { + case "bearer": + if (scheme.tokenEnvVar != null) { + environmentVariables.push(scheme.tokenEnvVar); + } + break; + case "header": + if (scheme.headerEnvVar != null) { + environmentVariables.push(scheme.headerEnvVar); + } + break; + case "basic": + if (scheme.usernameEnvVar != null) { + environmentVariables.push(scheme.usernameEnvVar); + } + if (scheme.passwordEnvVar != null) { + environmentVariables.push(scheme.passwordEnvVar); + } + break; + case "oauth": + if (scheme.configuration.type === "clientCredentials") { + if (scheme.configuration.clientIdEnvVar != null) { + environmentVariables.push(scheme.configuration.clientIdEnvVar); + } + if (scheme.configuration.clientSecretEnvVar != null) { + environmentVariables.push(scheme.configuration.clientSecretEnvVar); + } + } + break; + case "inferred": + break; + default: + assertNever(scheme); + } + } + return environmentVariables; + } + private getPrerenderedSnippetsForFeature( featureId: FernGeneratorCli.FeatureId, predicate: (endpoint: EndpointWithFilepath) => boolean = () => true @@ -176,23 +245,82 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder { } private renderRequestOptionsSnippet(endpoint: EndpointWithFilepath): string { - return this.writeCode(dedent` - // Specify default options applied on every request. - ${ReadmeSnippetBuilder.CLIENT_VARIABLE_NAME} := ${this.rootPackageClientName}.NewClient( - option.${this.getBearerTokenOptionName()}("${this.getTokenPlaceholder()}"), + const authOptions = this.getAuthOptions(); + const clientOptions = [ + ...authOptions, + dedent` option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, }, - ), - ) + )` + ]; + const requestOption = authOptions[0] ?? "option.WithMaxAttempts(1)"; + const lines: string[] = [ + "// Specify default options applied on every request.", + `${ReadmeSnippetBuilder.CLIENT_VARIABLE_NAME} := ${this.rootPackageClientName}.NewClient(`, + ...clientOptions.map((option) => `${this.indent(option)},`), + ")", + "", + "// Specify options for an individual request.", + `response, err := ${this.getMethodCall(endpoint)}(`, + " ...,", + ` ${requestOption},`, + ")" + ]; + return this.writeCode(lines.join("\n")); + } + + private getAuthOptions(): string[] { + const options: string[] = []; + for (const scheme of this.context.ir.auth?.schemes ?? []) { + switch (scheme.type) { + case "bearer": + options.push( + `option.With${this.context.caseConverter.pascalUnsafe(scheme.token)}("${ + scheme.tokenPlaceholder ?? "" + }")` + ); + break; + case "header": + options.push( + `option.With${this.context.caseConverter.pascalUnsafe(scheme.name)}("${ + scheme.headerPlaceholder ?? "" + }")` + ); + break; + case "basic": { + const basicAuthArguments: string[] = []; + if (scheme.usernameOmit !== true) { + basicAuthArguments.push(`"${scheme.usernamePlaceholder ?? ""}"`); + } + if (scheme.passwordOmit !== true) { + basicAuthArguments.push(`"${scheme.passwordPlaceholder ?? ""}"`); + } + if (basicAuthArguments.length > 0) { + options.push(`option.WithBasicAuth(${basicAuthArguments.join(", ")})`); + } + break; + } + case "oauth": + options.push( + `option.WithClientCredentials("${this.getOAuthClientIdPlaceholder()}", "${this.getOAuthClientSecretPlaceholder()}")` + ); + break; + case "inferred": + break; + default: + assertNever(scheme); + } + } + return options; + } - // Specify options for an individual request. - response, err := ${this.getMethodCall(endpoint)}( - ..., - option.${this.getBearerTokenOptionName()}("${this.getTokenPlaceholder()}"), - ) - `); + private indent(s: string): string { + return s + .split("\n") + .map((line) => (line.length > 0 ? ` ${line}` : line)) + .join("\n"); } private renderErrorsSnippet(endpoint: EndpointWithFilepath): string { @@ -200,7 +328,7 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder { response, err := ${this.getMethodCall(endpoint)}(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -282,8 +410,7 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder { } // Paginated endpoints return a Page with directly accessible headers, status code, and full response - ctx := context.TODO() - page, err := ${this.getMethodCall(endpoint)}( + page, err = ${this.getMethodCall(endpoint)}( ctx, ... ) @@ -407,8 +534,27 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder { } private getEndpointsForFeature(featureId: FernIr.FeatureId): EndpointWithFilepath[] { - const endpointIds = this.getConfiguredEndpointIdsForFeature(featureId) ?? [this.defaultEndpointId]; - return endpointIds.map(this.lookupEndpointById.bind(this)); + const configuredEndpointIds = this.getConfiguredEndpointIdsForFeature(featureId); + if (configuredEndpointIds != null) { + return configuredEndpointIds.map(this.lookupEndpointById.bind(this)); + } + if (featureId === FernGeneratorCli.StructuredFeatureId.Pagination) { + const paginatedEndpoint = this.getEndpointWithPagination(); + if (paginatedEndpoint != null) { + return [paginatedEndpoint]; + } + } + return [this.lookupEndpointById(this.defaultEndpointId)]; + } + + private getEndpointWithPagination(): EndpointWithFilepath | undefined { + const defaultEndpoint = this.endpointsById[this.defaultEndpointId]; + if (defaultEndpoint != null && this.context.isEnabledPaginationEndpoint(defaultEndpoint.endpoint)) { + return defaultEndpoint; + } + return Object.values(this.endpointsById).find((endpoint) => + this.context.isEnabledPaginationEndpoint(endpoint.endpoint) + ); } private getConfiguredEndpointIdsForFeature(featureId: FernIr.FeatureId): FernIr.EndpointId[] | undefined { diff --git a/generators/go/sdk/changes/unreleased/fix-readme-snippets.yml b/generators/go/sdk/changes/unreleased/fix-readme-snippets.yml new file mode 100644 index 000000000000..d5bcb596191e --- /dev/null +++ b/generators/go/sdk/changes/unreleased/fix-readme-snippets.yml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json + +- summary: | + Fix several issues in the generated README: + - The Request Options example now renders the auth options the SDK actually + generates (e.g., `option.WithSecret` for header auth, `option.WithBasicAuth` + for basic auth) instead of always assuming `option.WithToken`. + - The Errors example now passes a pointer to `errors.As` so the snippet + compiles and doesn't panic. + - The Pagination section is now emitted whenever the API has an endpoint + with a generated paginated client, by selecting such an endpoint for the + example, rather than relying on the default endpoint being paginated. The + section is omitted entirely when no paginated client is generated (e.g. + custom, URI, and path pagination), so the example no longer references an + iterator that doesn't exist. + - The Request Options section now documents the environment variables the + generated client reads credentials from when they aren't explicitly provided. + type: fix diff --git a/seed/go-sdk/accept-header/README.md b/seed/go-sdk/accept-header/README.md index e0ad93ea14df..881414088c9b 100644 --- a/seed/go-sdk/accept-header/README.md +++ b/seed/go-sdk/accept-header/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.Endpoint(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/alias-extends/README.md b/seed/go-sdk/alias-extends/README.md index 55fda3e38f2e..fa950b0ae1a5 100644 --- a/seed/go-sdk/alias-extends/README.md +++ b/seed/go-sdk/alias-extends/README.md @@ -69,7 +69,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.ExtendedInlineRequestBody(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -91,7 +91,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -102,7 +101,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.ExtendedInlineRequestBody( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/alias/README.md b/seed/go-sdk/alias/README.md index 61507e6ea97e..c17aad11c9d5 100644 --- a/seed/go-sdk/alias/README.md +++ b/seed/go-sdk/alias/README.md @@ -64,7 +64,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Get(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -86,7 +86,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -97,7 +96,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Get( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/allof-inline/README.md b/seed/go-sdk/allof-inline/README.md index 100f4e3e95f0..c038a83aeff4 100644 --- a/seed/go-sdk/allof-inline/README.md +++ b/seed/go-sdk/allof-inline/README.md @@ -69,7 +69,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.CreateRule(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -91,7 +91,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -102,7 +101,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.CreateRule( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/allof/README.md b/seed/go-sdk/allof/README.md index a87b13c5666f..4767441385b6 100644 --- a/seed/go-sdk/allof/README.md +++ b/seed/go-sdk/allof/README.md @@ -69,7 +69,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.CreateRule(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -91,7 +91,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -102,7 +101,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.CreateRule( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/any-auth/README.md b/seed/go-sdk/any-auth/README.md index a3a2ac55e9bf..8d38df44cd57 100644 --- a/seed/go-sdk/any-auth/README.md +++ b/seed/go-sdk/any-auth/README.md @@ -100,7 +100,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -123,6 +123,9 @@ specified on the client so that they're applied on every request, or for an indi // Specify default options applied on every request. client := client.NewClient( option.WithToken(""), + option.WithAPIKey(""), + option.WithClientCredentials("", ""), + option.WithBasicAuth("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -137,6 +140,16 @@ response, err := client.Auth.GetToken( ) ``` +When credentials are not explicitly provided, the client reads them from the +following environment variables: + +- `MY_TOKEN` +- `MY_API_KEY` +- `MY_CLIENT_ID` +- `MY_CLIENT_SECRET` +- `MY_USERNAME` +- `MY_PASSWORD` + ## Advanced ### Response Headers diff --git a/seed/go-sdk/api-wide-base-path-with-default/README.md b/seed/go-sdk/api-wide-base-path-with-default/README.md index 98fed6beba6c..46dab9923ca3 100644 --- a/seed/go-sdk/api-wide-base-path-with-default/README.md +++ b/seed/go-sdk/api-wide-base-path-with-default/README.md @@ -69,7 +69,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Widgets.Create(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -91,7 +91,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -102,7 +101,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Widgets.Create( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/api-wide-base-path/README.md b/seed/go-sdk/api-wide-base-path/README.md index 61f6b1aa0f7a..d2a54c60c79c 100644 --- a/seed/go-sdk/api-wide-base-path/README.md +++ b/seed/go-sdk/api-wide-base-path/README.md @@ -67,7 +67,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.Post(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -89,7 +89,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -100,7 +99,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.Post( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/audiences/README.md b/seed/go-sdk/audiences/README.md index 8dff682ef44e..4472527968bb 100644 --- a/seed/go-sdk/audiences/README.md +++ b/seed/go-sdk/audiences/README.md @@ -76,7 +76,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Foo.Find(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -98,7 +98,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -109,7 +108,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Foo.Find( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/basic-auth-environment-variables/README.md b/seed/go-sdk/basic-auth-environment-variables/README.md index de65b942a539..717943878e0a 100644 --- a/seed/go-sdk/basic-auth-environment-variables/README.md +++ b/seed/go-sdk/basic-auth-environment-variables/README.md @@ -73,7 +73,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.BasicAuth.PostWithBasicAuth(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -95,7 +95,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithBasicAuth("YOUR_USERNAME", "YOUR_PASSWORD"), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -106,10 +106,16 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.BasicAuth.PostWithBasicAuth( ..., - option.WithToken(""), + option.WithBasicAuth("YOUR_USERNAME", "YOUR_PASSWORD"), ) ``` +When credentials are not explicitly provided, the client reads them from the +following environment variables: + +- `USERNAME` +- `PASSWORD` + ## Advanced ### Response Headers diff --git a/seed/go-sdk/basic-auth-pw-omitted/wire-tests/README.md b/seed/go-sdk/basic-auth-pw-omitted/wire-tests/README.md index af5078f9ee46..2762e413a25a 100644 --- a/seed/go-sdk/basic-auth-pw-omitted/wire-tests/README.md +++ b/seed/go-sdk/basic-auth-pw-omitted/wire-tests/README.md @@ -72,7 +72,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.BasicAuth.PostWithBasicAuth(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -94,7 +94,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithBasicAuth(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -105,7 +105,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.BasicAuth.PostWithBasicAuth( ..., - option.WithToken(""), + option.WithBasicAuth(""), ) ``` diff --git a/seed/go-sdk/basic-auth/README.md b/seed/go-sdk/basic-auth/README.md index d494f9168313..ce300f615b79 100644 --- a/seed/go-sdk/basic-auth/README.md +++ b/seed/go-sdk/basic-auth/README.md @@ -73,7 +73,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.BasicAuth.PostWithBasicAuth(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -95,7 +95,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithBasicAuth("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -106,7 +106,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.BasicAuth.PostWithBasicAuth( ..., - option.WithToken(""), + option.WithBasicAuth("", ""), ) ``` diff --git a/seed/go-sdk/bearer-token-environment-variable/README.md b/seed/go-sdk/bearer-token-environment-variable/README.md index 6108426bf72b..f4fa8a0f03a0 100644 --- a/seed/go-sdk/bearer-token-environment-variable/README.md +++ b/seed/go-sdk/bearer-token-environment-variable/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.GetWithBearerToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithApiKey("YOUR_API_KEY"), + option.WithAPIKey("YOUR_API_KEY"), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,10 +101,15 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.GetWithBearerToken( ..., - option.WithApiKey("YOUR_API_KEY"), + option.WithAPIKey("YOUR_API_KEY"), ) ``` +When credentials are not explicitly provided, the client reads them from the +following environment variables: + +- `COURIER_API_KEY` + ## Advanced ### Response Headers diff --git a/seed/go-sdk/bytes-download/README.md b/seed/go-sdk/bytes-download/README.md index 5af8964fcc06..0308b4d2aaff 100644 --- a/seed/go-sdk/bytes-download/README.md +++ b/seed/go-sdk/bytes-download/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.Simple(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.Simple( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/bytes-upload/README.md b/seed/go-sdk/bytes-upload/README.md index 211fdde36a28..ed4f792a2050 100644 --- a/seed/go-sdk/bytes-upload/README.md +++ b/seed/go-sdk/bytes-upload/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.Upload(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.Upload( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/client-side-params/README.md b/seed/go-sdk/client-side-params/README.md index b35b33c7539b..81bfa9e3ae7a 100644 --- a/seed/go-sdk/client-side-params/README.md +++ b/seed/go-sdk/client-side-params/README.md @@ -82,7 +82,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.SearchResources(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/content-type/README.md b/seed/go-sdk/content-type/README.md index 34ac385ae6cc..84b5ec2dc73f 100644 --- a/seed/go-sdk/content-type/README.md +++ b/seed/go-sdk/content-type/README.md @@ -73,7 +73,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.Patch(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -95,7 +95,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -106,7 +105,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.Patch( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/cross-package-type-names/README.md b/seed/go-sdk/cross-package-type-names/README.md index 5a110e963fdf..66ac26ff9616 100644 --- a/seed/go-sdk/cross-package-type-names/README.md +++ b/seed/go-sdk/cross-package-type-names/README.md @@ -76,7 +76,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Foo.Find(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -98,7 +98,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -109,7 +108,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Foo.Find( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/discriminated-union-with-nested-oneof/README.md b/seed/go-sdk/discriminated-union-with-nested-oneof/README.md index b71ece35ec87..245c7902a2e2 100644 --- a/seed/go-sdk/discriminated-union-with-nested-oneof/README.md +++ b/seed/go-sdk/discriminated-union-with-nested-oneof/README.md @@ -70,7 +70,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.CreateAst(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -92,7 +92,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -103,7 +102,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.CreateAst( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/endpoint-security-auth/README.md b/seed/go-sdk/endpoint-security-auth/README.md index 708eede2851c..1182a8036637 100644 --- a/seed/go-sdk/endpoint-security-auth/README.md +++ b/seed/go-sdk/endpoint-security-auth/README.md @@ -100,7 +100,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -123,6 +123,9 @@ specified on the client so that they're applied on every request, or for an indi // Specify default options applied on every request. client := client.NewClient( option.WithToken(""), + option.WithAPIKey(""), + option.WithClientCredentials("", ""), + option.WithBasicAuth("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -137,6 +140,16 @@ response, err := client.Auth.GetToken( ) ``` +When credentials are not explicitly provided, the client reads them from the +following environment variables: + +- `MY_TOKEN` +- `MY_API_KEY` +- `MY_CLIENT_ID` +- `MY_CLIENT_SECRET` +- `MY_USERNAME` +- `MY_PASSWORD` + ## Advanced ### Response Headers diff --git a/seed/go-sdk/enum/README.md b/seed/go-sdk/enum/README.md index a418b09f4256..e15207e5fd0c 100644 --- a/seed/go-sdk/enum/README.md +++ b/seed/go-sdk/enum/README.md @@ -72,7 +72,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Headers.Send(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -94,7 +94,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -105,7 +104,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Headers.Send( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/error-property/README.md b/seed/go-sdk/error-property/README.md index d38de6f9c0fb..4ed0428c2100 100644 --- a/seed/go-sdk/error-property/README.md +++ b/seed/go-sdk/error-property/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.PropertyBasedError.ThrowError(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.PropertyBasedError.ThrowError( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/errors/README.md b/seed/go-sdk/errors/README.md index 14a8df7b30d9..2e38df6be899 100644 --- a/seed/go-sdk/errors/README.md +++ b/seed/go-sdk/errors/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Simple.FooWithoutEndpointError(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Simple.FooWithoutEndpointError( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/examples/always-send-required-properties/README.md b/seed/go-sdk/examples/always-send-required-properties/README.md index e45f92884eb5..bc711176beef 100644 --- a/seed/go-sdk/examples/always-send-required-properties/README.md +++ b/seed/go-sdk/examples/always-send-required-properties/README.md @@ -70,7 +70,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Echo(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/examples/client-name-with-custom-constructor-name/README.md b/seed/go-sdk/examples/client-name-with-custom-constructor-name/README.md index fd276a1e00ee..2aad4c90764f 100644 --- a/seed/go-sdk/examples/client-name-with-custom-constructor-name/README.md +++ b/seed/go-sdk/examples/client-name-with-custom-constructor-name/README.md @@ -70,7 +70,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Echo(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/examples/client-name/README.md b/seed/go-sdk/examples/client-name/README.md index 0f7db8e06213..2f15f2fc3543 100644 --- a/seed/go-sdk/examples/client-name/README.md +++ b/seed/go-sdk/examples/client-name/README.md @@ -70,7 +70,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Echo(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/examples/export-all-requests-at-root/README.md b/seed/go-sdk/examples/export-all-requests-at-root/README.md index e45f92884eb5..bc711176beef 100644 --- a/seed/go-sdk/examples/export-all-requests-at-root/README.md +++ b/seed/go-sdk/examples/export-all-requests-at-root/README.md @@ -70,7 +70,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Echo(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/examples/exported-client-name/README.md b/seed/go-sdk/examples/exported-client-name/README.md index 5762a7df3993..6e6b3b59a8ba 100644 --- a/seed/go-sdk/examples/exported-client-name/README.md +++ b/seed/go-sdk/examples/exported-client-name/README.md @@ -70,7 +70,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Echo(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/examples/getters-pass-by-value/README.md b/seed/go-sdk/examples/getters-pass-by-value/README.md index e45f92884eb5..bc711176beef 100644 --- a/seed/go-sdk/examples/getters-pass-by-value/README.md +++ b/seed/go-sdk/examples/getters-pass-by-value/README.md @@ -70,7 +70,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Echo(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/examples/no-custom-config/README.md b/seed/go-sdk/examples/no-custom-config/README.md index e45f92884eb5..bc711176beef 100644 --- a/seed/go-sdk/examples/no-custom-config/README.md +++ b/seed/go-sdk/examples/no-custom-config/README.md @@ -70,7 +70,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Echo(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/examples/package-path/README.md b/seed/go-sdk/examples/package-path/README.md index d4fc08d4d867..ef9dc46c281b 100644 --- a/seed/go-sdk/examples/package-path/README.md +++ b/seed/go-sdk/examples/package-path/README.md @@ -70,7 +70,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Echo(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/examples/readme-config/README.md b/seed/go-sdk/examples/readme-config/README.md index 3daca00443e0..5f342812e448 100644 --- a/seed/go-sdk/examples/readme-config/README.md +++ b/seed/go-sdk/examples/readme-config/README.md @@ -312,7 +312,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.CreateBigEntity(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/examples/v0/README.md b/seed/go-sdk/examples/v0/README.md index e45f92884eb5..bc711176beef 100644 --- a/seed/go-sdk/examples/v0/README.md +++ b/seed/go-sdk/examples/v0/README.md @@ -70,7 +70,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Echo(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/exhaustive/no-custom-config/README.md b/seed/go-sdk/exhaustive/no-custom-config/README.md index 202989b61c80..ba46523777ce 100644 --- a/seed/go-sdk/exhaustive/no-custom-config/README.md +++ b/seed/go-sdk/exhaustive/no-custom-config/README.md @@ -9,6 +9,7 @@ The Seed Go library provides convenient access to the Seed APIs from Go. - [Reference](#reference) - [Usage](#usage) - [Environments](#environments) +- [Pagination](#pagination) - [Errors](#errors) - [Request Options](#request-options) - [Advanced](#advanced) @@ -64,6 +65,71 @@ client := client.NewClient( ) ``` +## Pagination + +List endpoints are paginated. The SDK provides an iterator so that you can simply loop over the items. +You can also iterate page-by-page using the `GetNextPage` helper method. + +The `Page.Results` attribute, which contains the relevant list of items returned by the call to the server, +is the only attribute you will need for most use cases. But if need be, several other attributes are available: + +- `Page.Response` contains the full spec-defined response as returned by the server. +- `Page.StatusCode` and `Page.Header` returns HTTP metadata associated with the call to the server. +- `Page.RawResponse` returns the pagination object if you need to access its fields (like `Next`). + +```go +// Loop over the items using the provided iterator. +ctx := context.TODO() +page, err := client.Endpoints.Pagination.ListItems( + ctx, + ... +) +if err != nil { + return err +} +iter := page.Iterator() +for iter.Next(ctx) { + item := iter.Current() + fmt.Printf("Got item: %v", *item) +} +if err := iter.Err(); err != nil { + return err +} + +// Alternatively, iterate page-by-page. +for page != nil { + for _, item := range page.Results { + fmt.Printf("Got item: %v", *item) + } + page, err = page.GetNextPage(ctx) + if errors.Is(err, core.ErrNoPages) { + break + } + if err != nil { + return err + } +} + +// Paginated endpoints return a Page with directly accessible headers, status code, and full response +page, err = client.Endpoints.Pagination.ListItems( + ctx, + ... +) +if err != nil { + return err +} + +// Access response metadata directly from the page +fmt.Printf("Got headers: %v", page.Header) +fmt.Printf("Got status code: %d", page.StatusCode) + +// Access the full spec-defined response object +fullResponse := page.Response + +// Access individual fields from the pagination object +nextCursor := page.RawResponse.Next +``` + ## Errors Structured error types are returned from API calls that return non-success status codes. These errors are compatible @@ -73,7 +139,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Endpoints.Container.GetAndReturnListOfPrimitives(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/exhaustive/omit-empty-request-wrappers/README.md b/seed/go-sdk/exhaustive/omit-empty-request-wrappers/README.md index 202989b61c80..ba46523777ce 100644 --- a/seed/go-sdk/exhaustive/omit-empty-request-wrappers/README.md +++ b/seed/go-sdk/exhaustive/omit-empty-request-wrappers/README.md @@ -9,6 +9,7 @@ The Seed Go library provides convenient access to the Seed APIs from Go. - [Reference](#reference) - [Usage](#usage) - [Environments](#environments) +- [Pagination](#pagination) - [Errors](#errors) - [Request Options](#request-options) - [Advanced](#advanced) @@ -64,6 +65,71 @@ client := client.NewClient( ) ``` +## Pagination + +List endpoints are paginated. The SDK provides an iterator so that you can simply loop over the items. +You can also iterate page-by-page using the `GetNextPage` helper method. + +The `Page.Results` attribute, which contains the relevant list of items returned by the call to the server, +is the only attribute you will need for most use cases. But if need be, several other attributes are available: + +- `Page.Response` contains the full spec-defined response as returned by the server. +- `Page.StatusCode` and `Page.Header` returns HTTP metadata associated with the call to the server. +- `Page.RawResponse` returns the pagination object if you need to access its fields (like `Next`). + +```go +// Loop over the items using the provided iterator. +ctx := context.TODO() +page, err := client.Endpoints.Pagination.ListItems( + ctx, + ... +) +if err != nil { + return err +} +iter := page.Iterator() +for iter.Next(ctx) { + item := iter.Current() + fmt.Printf("Got item: %v", *item) +} +if err := iter.Err(); err != nil { + return err +} + +// Alternatively, iterate page-by-page. +for page != nil { + for _, item := range page.Results { + fmt.Printf("Got item: %v", *item) + } + page, err = page.GetNextPage(ctx) + if errors.Is(err, core.ErrNoPages) { + break + } + if err != nil { + return err + } +} + +// Paginated endpoints return a Page with directly accessible headers, status code, and full response +page, err = client.Endpoints.Pagination.ListItems( + ctx, + ... +) +if err != nil { + return err +} + +// Access response metadata directly from the page +fmt.Printf("Got headers: %v", page.Header) +fmt.Printf("Got status code: %d", page.StatusCode) + +// Access the full spec-defined response object +fullResponse := page.Response + +// Access individual fields from the pagination object +nextCursor := page.RawResponse.Next +``` + ## Errors Structured error types are returned from API calls that return non-success status codes. These errors are compatible @@ -73,7 +139,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Endpoints.Container.GetAndReturnListOfPrimitives(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/extends/README.md b/seed/go-sdk/extends/README.md index 6046324c2483..abb3f6024669 100644 --- a/seed/go-sdk/extends/README.md +++ b/seed/go-sdk/extends/README.md @@ -70,7 +70,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.ExtendedInlineRequestBody(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -92,7 +92,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -103,7 +102,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.ExtendedInlineRequestBody( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/extra-properties/README.md b/seed/go-sdk/extra-properties/README.md index 5a823593befe..16fbfe36cd5f 100644 --- a/seed/go-sdk/extra-properties/README.md +++ b/seed/go-sdk/extra-properties/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.User.CreateUser(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.User.CreateUser( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/file-download/README.md b/seed/go-sdk/file-download/README.md index 85f6e0f38b24..70fc2690f319 100644 --- a/seed/go-sdk/file-download/README.md +++ b/seed/go-sdk/file-download/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.Simple(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.Simple( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/file-upload-openapi/README.md b/seed/go-sdk/file-upload-openapi/README.md index 572fda5c8e04..b372f17ada54 100644 --- a/seed/go-sdk/file-upload-openapi/README.md +++ b/seed/go-sdk/file-upload-openapi/README.md @@ -72,7 +72,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.FileUploadExample.UploadFile(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -94,7 +94,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -105,7 +104,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.FileUploadExample.UploadFile( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/file-upload/no-custom-config/README.md b/seed/go-sdk/file-upload/no-custom-config/README.md index 0ab907239b52..b08db769e15a 100644 --- a/seed/go-sdk/file-upload/no-custom-config/README.md +++ b/seed/go-sdk/file-upload/no-custom-config/README.md @@ -71,7 +71,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.JustFile(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -93,7 +93,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -104,7 +103,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.JustFile( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/file-upload/package-name/README.md b/seed/go-sdk/file-upload/package-name/README.md index 096183586448..418d7015c161 100644 --- a/seed/go-sdk/file-upload/package-name/README.md +++ b/seed/go-sdk/file-upload/package-name/README.md @@ -71,7 +71,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.JustFile(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -93,7 +93,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -104,7 +103,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.JustFile( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/file-upload/v0/README.md b/seed/go-sdk/file-upload/v0/README.md index b1392a4ec928..05dae7e6bdd6 100644 --- a/seed/go-sdk/file-upload/v0/README.md +++ b/seed/go-sdk/file-upload/v0/README.md @@ -67,7 +67,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.JustFile(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -89,7 +89,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -100,7 +99,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.JustFile( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/folders/README.md b/seed/go-sdk/folders/README.md index 83a47c8154ef..b5892d8b9df2 100644 --- a/seed/go-sdk/folders/README.md +++ b/seed/go-sdk/folders/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Foo(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Foo( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/go-content-type/README.md b/seed/go-sdk/go-content-type/README.md index de8bf4d4fa04..7b342806f9f4 100644 --- a/seed/go-sdk/go-content-type/README.md +++ b/seed/go-sdk/go-content-type/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Imdb.CreateMovie(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/go-date-containers/README.md b/seed/go-sdk/go-date-containers/README.md index 825e3ea54938..ca09705ac532 100644 --- a/seed/go-sdk/go-date-containers/README.md +++ b/seed/go-sdk/go-date-containers/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Loans.GetLoan(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Loans.GetLoan( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/go-deterministic-ordering/README.md b/seed/go-sdk/go-deterministic-ordering/README.md index f2a02cd869fc..cbbe2f913089 100644 --- a/seed/go-sdk/go-deterministic-ordering/README.md +++ b/seed/go-sdk/go-deterministic-ordering/README.md @@ -9,6 +9,7 @@ The Seed Go library provides convenient access to the Seed APIs from Go. - [Reference](#reference) - [Usage](#usage) - [Environments](#environments) +- [Pagination](#pagination) - [Errors](#errors) - [Request Options](#request-options) - [Advanced](#advanced) @@ -64,6 +65,71 @@ client := client.NewClient( ) ``` +## Pagination + +List endpoints are paginated. The SDK provides an iterator so that you can simply loop over the items. +You can also iterate page-by-page using the `GetNextPage` helper method. + +The `Page.Results` attribute, which contains the relevant list of items returned by the call to the server, +is the only attribute you will need for most use cases. But if need be, several other attributes are available: + +- `Page.Response` contains the full spec-defined response as returned by the server. +- `Page.StatusCode` and `Page.Header` returns HTTP metadata associated with the call to the server. +- `Page.RawResponse` returns the pagination object if you need to access its fields (like `Next`). + +```go +// Loop over the items using the provided iterator. +ctx := context.TODO() +page, err := client.Endpoints.Pagination.ListItems( + ctx, + ... +) +if err != nil { + return err +} +iter := page.Iterator() +for iter.Next(ctx) { + item := iter.Current() + fmt.Printf("Got item: %v", *item) +} +if err := iter.Err(); err != nil { + return err +} + +// Alternatively, iterate page-by-page. +for page != nil { + for _, item := range page.Results { + fmt.Printf("Got item: %v", *item) + } + page, err = page.GetNextPage(ctx) + if errors.Is(err, core.ErrNoPages) { + break + } + if err != nil { + return err + } +} + +// Paginated endpoints return a Page with directly accessible headers, status code, and full response +page, err = client.Endpoints.Pagination.ListItems( + ctx, + ... +) +if err != nil { + return err +} + +// Access response metadata directly from the page +fmt.Printf("Got headers: %v", page.Header) +fmt.Printf("Got status code: %d", page.StatusCode) + +// Access the full spec-defined response object +fullResponse := page.Response + +// Access individual fields from the pagination object +nextCursor := page.RawResponse.Next +``` + ## Errors Structured error types are returned from API calls that return non-success status codes. These errors are compatible @@ -73,7 +139,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Endpoints.Container.GetAndReturnListOfPrimitives(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/go-multi-env-url-templating/no-custom-config/README.md b/seed/go-sdk/go-multi-env-url-templating/no-custom-config/README.md index 9e1dc1afa970..859b75604d86 100644 --- a/seed/go-sdk/go-multi-env-url-templating/no-custom-config/README.md +++ b/seed/go-sdk/go-multi-env-url-templating/no-custom-config/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetToken( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/go-nullable-date-ref/README.md b/seed/go-sdk/go-nullable-date-ref/README.md index 3f4e1567f65c..0327f07f72d1 100644 --- a/seed/go-sdk/go-nullable-date-ref/README.md +++ b/seed/go-sdk/go-nullable-date-ref/README.md @@ -71,7 +71,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Reports.Create(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -93,7 +93,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -104,7 +103,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Reports.Create( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/go-nullable-wire-tests/README.md b/seed/go-sdk/go-nullable-wire-tests/README.md index c308cbbe7db0..e212f623f96e 100644 --- a/seed/go-sdk/go-nullable-wire-tests/README.md +++ b/seed/go-sdk/go-nullable-wire-tests/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Things.GetThing(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Things.GetThing( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/go-oauth-token-nullable/no-custom-config/README.md b/seed/go-sdk/go-oauth-token-nullable/no-custom-config/README.md index a5691a32e5ab..c596a0dd41ff 100644 --- a/seed/go-sdk/go-oauth-token-nullable/no-custom-config/README.md +++ b/seed/go-sdk/go-oauth-token-nullable/no-custom-config/README.md @@ -101,7 +101,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetTokenWithClientCredentials(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -123,7 +123,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithClientCredentials("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -134,7 +134,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetTokenWithClientCredentials( ..., - option.WithToken(""), + option.WithClientCredentials("", ""), ) ``` diff --git a/seed/go-sdk/go-oauth-token-optional/no-custom-config/README.md b/seed/go-sdk/go-oauth-token-optional/no-custom-config/README.md index f0943bb7adcd..fa266bd9ee56 100644 --- a/seed/go-sdk/go-oauth-token-optional/no-custom-config/README.md +++ b/seed/go-sdk/go-oauth-token-optional/no-custom-config/README.md @@ -104,7 +104,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.CreateOauth2Token(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -126,7 +126,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithClientCredentials("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -137,7 +137,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.CreateOauth2Token( ..., - option.WithToken(""), + option.WithClientCredentials("", ""), ) ``` diff --git a/seed/go-sdk/go-optional-header-env/README.md b/seed/go-sdk/go-optional-header-env/README.md index 22fe9e3e7dfa..dc6dee9ce7ba 100644 --- a/seed/go-sdk/go-optional-header-env/README.md +++ b/seed/go-sdk/go-optional-header-env/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.GetWithAPIVersion(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithApiKey(""), + option.WithAPIKey(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,10 +101,15 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.GetWithAPIVersion( ..., - option.WithApiKey(""), + option.WithAPIKey(""), ) ``` +When credentials are not explicitly provided, the client reads them from the +following environment variables: + +- `COURIER_API_KEY` + ## Advanced ### Response Headers diff --git a/seed/go-sdk/go-optional-literal-alias/README.md b/seed/go-sdk/go-optional-literal-alias/README.md index 5c5332c8127e..7c7abe5cfd47 100644 --- a/seed/go-sdk/go-optional-literal-alias/README.md +++ b/seed/go-sdk/go-optional-literal-alias/README.md @@ -71,7 +71,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Search(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -93,7 +93,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -104,7 +103,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Search( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/go-optional-request-body/no-custom-config/README.md b/seed/go-sdk/go-optional-request-body/no-custom-config/README.md index 8718e3bded27..190c7ca6064e 100644 --- a/seed/go-sdk/go-optional-request-body/no-custom-config/README.md +++ b/seed/go-sdk/go-optional-request-body/no-custom-config/README.md @@ -73,7 +73,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.WaterPlant(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -95,7 +95,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -106,7 +105,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.WaterPlant( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/go-optional-request-body/respect-optional-request-body/README.md b/seed/go-sdk/go-optional-request-body/respect-optional-request-body/README.md index 8718e3bded27..190c7ca6064e 100644 --- a/seed/go-sdk/go-optional-request-body/respect-optional-request-body/README.md +++ b/seed/go-sdk/go-optional-request-body/respect-optional-request-body/README.md @@ -73,7 +73,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.WaterPlant(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -95,7 +95,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -106,7 +105,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.WaterPlant( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/go-pagination-offset-item-index/README.md b/seed/go-sdk/go-pagination-offset-item-index/README.md index 707a2e6bcb44..b7b6f076fa72 100644 --- a/seed/go-sdk/go-pagination-offset-item-index/README.md +++ b/seed/go-sdk/go-pagination-offset-item-index/README.md @@ -111,8 +111,7 @@ for page != nil { } // Paginated endpoints return a Page with directly accessible headers, status code, and full response -ctx := context.TODO() -page, err := client.Plants.ListWithBodyOffset( +page, err = client.Plants.ListWithBodyOffset( ctx, ... ) @@ -140,7 +139,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Plants.ListWithBodyOffset(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -162,7 +161,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -173,7 +171,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Plants.ListWithBodyOffset( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/go-request-body-pagination/README.md b/seed/go-sdk/go-request-body-pagination/README.md index 8ac70f8146c6..b76acbee2dd9 100644 --- a/seed/go-sdk/go-request-body-pagination/README.md +++ b/seed/go-sdk/go-request-body-pagination/README.md @@ -111,8 +111,7 @@ for page != nil { } // Paginated endpoints return a Page with directly accessible headers, status code, and full response -ctx := context.TODO() -page, err := client.Users.ListWithBodyCursorPagination( +page, err = client.Users.ListWithBodyCursorPagination( ctx, ... ) @@ -140,7 +139,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Users.ListWithBodyCursorPagination(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -162,7 +161,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -173,7 +171,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Users.ListWithBodyCursorPagination( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/go-undiscriminated-union-wire-tests/README.md b/seed/go-sdk/go-undiscriminated-union-wire-tests/README.md index 8083c01b624d..992170e4bc56 100644 --- a/seed/go-sdk/go-undiscriminated-union-wire-tests/README.md +++ b/seed/go-sdk/go-undiscriminated-union-wire-tests/README.md @@ -85,7 +85,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.Rerank(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/go-union-base-properties/dedupe-union-base-properties/README.md b/seed/go-sdk/go-union-base-properties/dedupe-union-base-properties/README.md index ef0c08e4098d..63becb75f85a 100644 --- a/seed/go-sdk/go-union-base-properties/dedupe-union-base-properties/README.md +++ b/seed/go-sdk/go-union-base-properties/dedupe-union-base-properties/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Create(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -96,7 +96,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -107,7 +106,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Create( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/go-union-base-properties/no-custom-config/README.md b/seed/go-sdk/go-union-base-properties/no-custom-config/README.md index 7c2730229bf5..0481230d61b6 100644 --- a/seed/go-sdk/go-union-base-properties/no-custom-config/README.md +++ b/seed/go-sdk/go-union-base-properties/no-custom-config/README.md @@ -78,7 +78,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Create(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -100,7 +100,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -111,7 +110,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Create( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/header-auth-environment-variable/README.md b/seed/go-sdk/header-auth-environment-variable/README.md index 92bffa9e311b..ed4a9636ff09 100644 --- a/seed/go-sdk/header-auth-environment-variable/README.md +++ b/seed/go-sdk/header-auth-environment-variable/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.GetWithBearerToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken("YOUR_HEADER_VALUE"), + option.WithHeaderTokenAuth("YOUR_HEADER_VALUE"), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,10 +101,15 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.GetWithBearerToken( ..., - option.WithToken("YOUR_HEADER_VALUE"), + option.WithHeaderTokenAuth("YOUR_HEADER_VALUE"), ) ``` +When credentials are not explicitly provided, the client reads them from the +following environment variables: + +- `HEADER_TOKEN_ENV_VAR` + ## Advanced ### Response Headers diff --git a/seed/go-sdk/header-auth/README.md b/seed/go-sdk/header-auth/README.md index d5c4fef18240..36fd6a1ca038 100644 --- a/seed/go-sdk/header-auth/README.md +++ b/seed/go-sdk/header-auth/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.GetWithBearerToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken("YOUR_API_KEY"), + option.WithHeaderTokenAuth("YOUR_API_KEY"), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +101,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.GetWithBearerToken( ..., - option.WithToken("YOUR_API_KEY"), + option.WithHeaderTokenAuth("YOUR_API_KEY"), ) ``` diff --git a/seed/go-sdk/http-head/README.md b/seed/go-sdk/http-head/README.md index 6142ed7ff950..8d006870e8b9 100644 --- a/seed/go-sdk/http-head/README.md +++ b/seed/go-sdk/http-head/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.User.Head(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.User.Head( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/idempotency-headers/README.md b/seed/go-sdk/idempotency-headers/README.md index 0a7dbe5ee555..9597966de9ec 100644 --- a/seed/go-sdk/idempotency-headers/README.md +++ b/seed/go-sdk/idempotency-headers/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Payment.Create(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/idempotency-headers/auto-generate-idempotency-key/README.md b/seed/go-sdk/idempotency-headers/auto-generate-idempotency-key/README.md index 0a7dbe5ee555..9597966de9ec 100644 --- a/seed/go-sdk/idempotency-headers/auto-generate-idempotency-key/README.md +++ b/seed/go-sdk/idempotency-headers/auto-generate-idempotency-key/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Payment.Create(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/imdb/allow-user-agent-app-info/README.md b/seed/go-sdk/imdb/allow-user-agent-app-info/README.md index 66b3bed8a752..fc56610ca8da 100644 --- a/seed/go-sdk/imdb/allow-user-agent-app-info/README.md +++ b/seed/go-sdk/imdb/allow-user-agent-app-info/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Imdb.CreateMovie(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/imdb/deep-package-path/README.md b/seed/go-sdk/imdb/deep-package-path/README.md index b8e9f51ff249..766c2f53b15d 100644 --- a/seed/go-sdk/imdb/deep-package-path/README.md +++ b/seed/go-sdk/imdb/deep-package-path/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Imdb.CreateMovie(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/imdb/include-platform-headers-app-info/README.md b/seed/go-sdk/imdb/include-platform-headers-app-info/README.md index 66b3bed8a752..fc56610ca8da 100644 --- a/seed/go-sdk/imdb/include-platform-headers-app-info/README.md +++ b/seed/go-sdk/imdb/include-platform-headers-app-info/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Imdb.CreateMovie(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/imdb/include-platform-headers/README.md b/seed/go-sdk/imdb/include-platform-headers/README.md index 66b3bed8a752..fc56610ca8da 100644 --- a/seed/go-sdk/imdb/include-platform-headers/README.md +++ b/seed/go-sdk/imdb/include-platform-headers/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Imdb.CreateMovie(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/imdb/no-custom-config/README.md b/seed/go-sdk/imdb/no-custom-config/README.md index 66b3bed8a752..fc56610ca8da 100644 --- a/seed/go-sdk/imdb/no-custom-config/README.md +++ b/seed/go-sdk/imdb/no-custom-config/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Imdb.CreateMovie(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/imdb/omit-fern-headers/README.md b/seed/go-sdk/imdb/omit-fern-headers/README.md index 66b3bed8a752..fc56610ca8da 100644 --- a/seed/go-sdk/imdb/omit-fern-headers/README.md +++ b/seed/go-sdk/imdb/omit-fern-headers/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Imdb.CreateMovie(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/imdb/package-path/README.md b/seed/go-sdk/imdb/package-path/README.md index 9370df2105da..bdbc3922e473 100644 --- a/seed/go-sdk/imdb/package-path/README.md +++ b/seed/go-sdk/imdb/package-path/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Imdb.CreateMovie(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/imdb/with-wiremock-tests/README.md b/seed/go-sdk/imdb/with-wiremock-tests/README.md index 1d9cd344cd8a..1da519dfa60a 100644 --- a/seed/go-sdk/imdb/with-wiremock-tests/README.md +++ b/seed/go-sdk/imdb/with-wiremock-tests/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Imdb.CreateMovie(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/inferred-auth-explicit/README.md b/seed/go-sdk/inferred-auth-explicit/README.md index 33ea0288a63c..b5596d0ed41c 100644 --- a/seed/go-sdk/inferred-auth-explicit/README.md +++ b/seed/go-sdk/inferred-auth-explicit/README.md @@ -84,7 +84,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetTokenWithClientCredentials(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -106,7 +106,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -117,7 +116,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetTokenWithClientCredentials( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/inferred-auth-implicit-api-key/README.md b/seed/go-sdk/inferred-auth-implicit-api-key/README.md index 7100a0cdcff6..b66b20366ee0 100644 --- a/seed/go-sdk/inferred-auth-implicit-api-key/README.md +++ b/seed/go-sdk/inferred-auth-implicit-api-key/README.md @@ -73,7 +73,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -95,7 +95,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -106,7 +105,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetToken( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/inferred-auth-implicit-no-expiry/README.md b/seed/go-sdk/inferred-auth-implicit-no-expiry/README.md index 846c523bee52..a8b646c060bf 100644 --- a/seed/go-sdk/inferred-auth-implicit-no-expiry/README.md +++ b/seed/go-sdk/inferred-auth-implicit-no-expiry/README.md @@ -84,7 +84,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetTokenWithClientCredentials(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -106,7 +106,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -117,7 +116,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetTokenWithClientCredentials( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/inferred-auth-implicit-reference/README.md b/seed/go-sdk/inferred-auth-implicit-reference/README.md index 0a2af925c0dc..58de00ea9401 100644 --- a/seed/go-sdk/inferred-auth-implicit-reference/README.md +++ b/seed/go-sdk/inferred-auth-implicit-reference/README.md @@ -80,7 +80,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetTokenWithClientCredentials(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -102,7 +102,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -113,7 +112,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetTokenWithClientCredentials( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/inferred-auth-implicit/README.md b/seed/go-sdk/inferred-auth-implicit/README.md index ff5c11ed27bc..bbf279a6861c 100644 --- a/seed/go-sdk/inferred-auth-implicit/README.md +++ b/seed/go-sdk/inferred-auth-implicit/README.md @@ -86,7 +86,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetTokenWithClientCredentials(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -108,7 +108,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -119,7 +118,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetTokenWithClientCredentials( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/inline-enum-type-name-override/README.md b/seed/go-sdk/inline-enum-type-name-override/README.md index 4dde57074d60..d00119058426 100644 --- a/seed/go-sdk/inline-enum-type-name-override/README.md +++ b/seed/go-sdk/inline-enum-type-name-override/README.md @@ -66,7 +66,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Reporting.Load(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -88,7 +88,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -99,7 +98,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Reporting.Load( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/license/README.md b/seed/go-sdk/license/README.md index 896f4a524836..214ac37d5905 100644 --- a/seed/go-sdk/license/README.md +++ b/seed/go-sdk/license/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Get(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Get( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/literal-user-agent/README.md b/seed/go-sdk/literal-user-agent/README.md index a3c1228647ee..ecea0eff79e5 100644 --- a/seed/go-sdk/literal-user-agent/README.md +++ b/seed/go-sdk/literal-user-agent/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Ping(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Ping( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/literal/README.md b/seed/go-sdk/literal/README.md index 2d55af765105..89309e2d7ac8 100644 --- a/seed/go-sdk/literal/README.md +++ b/seed/go-sdk/literal/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Headers.Send(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Headers.Send( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/mixed-case/default-values/README.md b/seed/go-sdk/mixed-case/default-values/README.md index 964a8aebe681..0c4323f53b08 100644 --- a/seed/go-sdk/mixed-case/default-values/README.md +++ b/seed/go-sdk/mixed-case/default-values/README.md @@ -64,7 +64,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.GetResource(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -86,7 +86,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -97,7 +96,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.GetResource( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/mixed-case/no-custom-config/README.md b/seed/go-sdk/mixed-case/no-custom-config/README.md index 964a8aebe681..0c4323f53b08 100644 --- a/seed/go-sdk/mixed-case/no-custom-config/README.md +++ b/seed/go-sdk/mixed-case/no-custom-config/README.md @@ -64,7 +64,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.GetResource(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -86,7 +86,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -97,7 +96,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.GetResource( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/mixed-file-directory/README.md b/seed/go-sdk/mixed-file-directory/README.md index 3d347f0abc6e..6f4dfdc53f29 100644 --- a/seed/go-sdk/mixed-file-directory/README.md +++ b/seed/go-sdk/mixed-file-directory/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Organization.Create(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Organization.Create( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/multi-content-type-examples/README.md b/seed/go-sdk/multi-content-type-examples/README.md index f8fe0c3b9dc9..e34ec96dc264 100644 --- a/seed/go-sdk/multi-content-type-examples/README.md +++ b/seed/go-sdk/multi-content-type-examples/README.md @@ -71,7 +71,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Clients.Create(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -93,7 +93,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -104,7 +103,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Clients.Create( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/multi-line-docs/README.md b/seed/go-sdk/multi-line-docs/README.md index 98a261b671e4..d4820f378b0d 100644 --- a/seed/go-sdk/multi-line-docs/README.md +++ b/seed/go-sdk/multi-line-docs/README.md @@ -71,7 +71,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.User.CreateUser(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -93,7 +93,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -104,7 +103,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.User.CreateUser( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/multi-url-environment-no-default/README.md b/seed/go-sdk/multi-url-environment-no-default/README.md index 9bc8f59c8484..0b336fa8b1a8 100644 --- a/seed/go-sdk/multi-url-environment-no-default/README.md +++ b/seed/go-sdk/multi-url-environment-no-default/README.md @@ -73,7 +73,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Ec2.BootInstance(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/multi-url-environment-reference/README.md b/seed/go-sdk/multi-url-environment-reference/README.md index 56dacb0dc05a..ee77daead755 100644 --- a/seed/go-sdk/multi-url-environment-reference/README.md +++ b/seed/go-sdk/multi-url-environment-reference/README.md @@ -74,7 +74,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.Gettoken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/multi-url-environment/README.md b/seed/go-sdk/multi-url-environment/README.md index 457782cef6c6..ba99453d0361 100644 --- a/seed/go-sdk/multi-url-environment/README.md +++ b/seed/go-sdk/multi-url-environment/README.md @@ -73,7 +73,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Ec2.BootInstance(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/multiple-request-bodies/README.md b/seed/go-sdk/multiple-request-bodies/README.md index 466a4f4bf38d..1dc83c84e582 100644 --- a/seed/go-sdk/multiple-request-bodies/README.md +++ b/seed/go-sdk/multiple-request-bodies/README.md @@ -71,7 +71,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.UploadJSONDocument(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/no-content-response/README.md b/seed/go-sdk/no-content-response/README.md index a7536430bebf..da57e7f5fbba 100644 --- a/seed/go-sdk/no-content-response/README.md +++ b/seed/go-sdk/no-content-response/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Contacts.Create(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Contacts.Create( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/no-environment/README.md b/seed/go-sdk/no-environment/README.md index 60c4bd0d95cb..5a0b4581c547 100644 --- a/seed/go-sdk/no-environment/README.md +++ b/seed/go-sdk/no-environment/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Dummy.GetDummy(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/no-retries/README.md b/seed/go-sdk/no-retries/README.md index 0755842d5196..6584b8715d70 100644 --- a/seed/go-sdk/no-retries/README.md +++ b/seed/go-sdk/no-retries/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Retries.GetUsers(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Retries.GetUsers( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/null-type/README.md b/seed/go-sdk/null-type/README.md index 5ca1aa973ac8..56b2a6c2ff19 100644 --- a/seed/go-sdk/null-type/README.md +++ b/seed/go-sdk/null-type/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Conversations.OutboundCall(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Conversations.OutboundCall( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/nullable-allof-extends/README.md b/seed/go-sdk/nullable-allof-extends/README.md index 780bdecf0161..2ac75b0590db 100644 --- a/seed/go-sdk/nullable-allof-extends/README.md +++ b/seed/go-sdk/nullable-allof-extends/README.md @@ -66,7 +66,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.CreateTest(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -88,7 +88,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -99,7 +98,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.CreateTest( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/nullable-optional/README.md b/seed/go-sdk/nullable-optional/README.md index 603ef9d3574a..1fead791839f 100644 --- a/seed/go-sdk/nullable-optional/README.md +++ b/seed/go-sdk/nullable-optional/README.md @@ -93,7 +93,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.NullableOptional.CreateUser(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -115,7 +115,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -126,7 +125,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.NullableOptional.CreateUser( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/nullable-request-body/dynamic-snippets-disabled/README.md b/seed/go-sdk/nullable-request-body/dynamic-snippets-disabled/README.md index 32f56dbcd586..d841fea7aa1c 100644 --- a/seed/go-sdk/nullable-request-body/dynamic-snippets-disabled/README.md +++ b/seed/go-sdk/nullable-request-body/dynamic-snippets-disabled/README.md @@ -69,7 +69,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.TestGroup.TestMethodName(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -91,7 +91,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -102,7 +101,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.TestGroup.TestMethodName( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/nullable/README.md b/seed/go-sdk/nullable/README.md index 0ff14bf57711..031401d3d566 100644 --- a/seed/go-sdk/nullable/README.md +++ b/seed/go-sdk/nullable/README.md @@ -97,7 +97,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Nullable.CreateUser(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -119,7 +119,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -130,7 +129,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Nullable.CreateUser( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/oauth-client-credentials-custom/README.md b/seed/go-sdk/oauth-client-credentials-custom/README.md index c5479b5612ba..dfd485309614 100644 --- a/seed/go-sdk/oauth-client-credentials-custom/README.md +++ b/seed/go-sdk/oauth-client-credentials-custom/README.md @@ -110,7 +110,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetTokenWithClientCredentials(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -132,7 +132,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithClientCredentials("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -143,7 +143,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetTokenWithClientCredentials( ..., - option.WithToken(""), + option.WithClientCredentials("", ""), ) ``` diff --git a/seed/go-sdk/oauth-client-credentials-default/README.md b/seed/go-sdk/oauth-client-credentials-default/README.md index a45d47d42540..dc36a38a5653 100644 --- a/seed/go-sdk/oauth-client-credentials-default/README.md +++ b/seed/go-sdk/oauth-client-credentials-default/README.md @@ -101,7 +101,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -123,7 +123,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithClientCredentials("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -134,7 +134,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetToken( ..., - option.WithToken(""), + option.WithClientCredentials("", ""), ) ``` diff --git a/seed/go-sdk/oauth-client-credentials-environment-variables/README.md b/seed/go-sdk/oauth-client-credentials-environment-variables/README.md index 2f2baaaceafb..83f2c67ef050 100644 --- a/seed/go-sdk/oauth-client-credentials-environment-variables/README.md +++ b/seed/go-sdk/oauth-client-credentials-environment-variables/README.md @@ -104,7 +104,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetTokenWithClientCredentials(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -126,7 +126,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithClientCredentials("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -137,10 +137,16 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetTokenWithClientCredentials( ..., - option.WithToken(""), + option.WithClientCredentials("", ""), ) ``` +When credentials are not explicitly provided, the client reads them from the +following environment variables: + +- `CLIENT_ID` +- `CLIENT_SECRET` + ## Advanced ### Response Headers diff --git a/seed/go-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/README.md b/seed/go-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/README.md index 472a566c0230..022589ca84f5 100644 --- a/seed/go-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/README.md +++ b/seed/go-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/README.md @@ -104,7 +104,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetTokenWithClientCredentials(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -126,7 +126,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithClientCredentials("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -137,7 +137,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetTokenWithClientCredentials( ..., - option.WithToken(""), + option.WithClientCredentials("", ""), ) ``` diff --git a/seed/go-sdk/oauth-client-credentials-nested-root/README.md b/seed/go-sdk/oauth-client-credentials-nested-root/README.md index 37609b353c17..29ce2ceb6a85 100644 --- a/seed/go-sdk/oauth-client-credentials-nested-root/README.md +++ b/seed/go-sdk/oauth-client-credentials-nested-root/README.md @@ -105,7 +105,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -127,7 +127,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithClientCredentials("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -138,7 +138,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetToken( ..., - option.WithToken(""), + option.WithClientCredentials("", ""), ) ``` diff --git a/seed/go-sdk/oauth-client-credentials-openapi/README.md b/seed/go-sdk/oauth-client-credentials-openapi/README.md index 57c373ceb46b..f84398c42e48 100644 --- a/seed/go-sdk/oauth-client-credentials-openapi/README.md +++ b/seed/go-sdk/oauth-client-credentials-openapi/README.md @@ -101,7 +101,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Identity.GetToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -123,7 +123,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithClientCredentials("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -134,7 +134,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Identity.GetToken( ..., - option.WithToken(""), + option.WithClientCredentials("", ""), ) ``` diff --git a/seed/go-sdk/oauth-client-credentials-reference/README.md b/seed/go-sdk/oauth-client-credentials-reference/README.md index ad48ce4b6dcb..49bee4f09e4a 100644 --- a/seed/go-sdk/oauth-client-credentials-reference/README.md +++ b/seed/go-sdk/oauth-client-credentials-reference/README.md @@ -101,7 +101,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -123,7 +123,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithClientCredentials("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -134,7 +134,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetToken( ..., - option.WithToken(""), + option.WithClientCredentials("", ""), ) ``` diff --git a/seed/go-sdk/oauth-client-credentials-with-variables/README.md b/seed/go-sdk/oauth-client-credentials-with-variables/README.md index 6af70e58280e..7b31ef6bcb91 100644 --- a/seed/go-sdk/oauth-client-credentials-with-variables/README.md +++ b/seed/go-sdk/oauth-client-credentials-with-variables/README.md @@ -104,7 +104,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetTokenWithClientCredentials(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -126,7 +126,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithClientCredentials("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -137,7 +137,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetTokenWithClientCredentials( ..., - option.WithToken(""), + option.WithClientCredentials("", ""), ) ``` diff --git a/seed/go-sdk/oauth-client-credentials/README.md b/seed/go-sdk/oauth-client-credentials/README.md index b783e72c6098..dab117f59409 100644 --- a/seed/go-sdk/oauth-client-credentials/README.md +++ b/seed/go-sdk/oauth-client-credentials/README.md @@ -104,7 +104,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetTokenWithClientCredentials(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -126,7 +126,7 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), + option.WithClientCredentials("", ""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -137,7 +137,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetTokenWithClientCredentials( ..., - option.WithToken(""), + option.WithClientCredentials("", ""), ) ``` diff --git a/seed/go-sdk/oauth-pkce/README.md b/seed/go-sdk/oauth-pkce/README.md index fa062aa47006..faaec0cbc761 100644 --- a/seed/go-sdk/oauth-pkce/README.md +++ b/seed/go-sdk/oauth-pkce/README.md @@ -79,7 +79,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Oauth.Authorize(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -101,7 +101,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -112,7 +111,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Oauth.Authorize( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/openapi-path-param-body-collision/README.md b/seed/go-sdk/openapi-path-param-body-collision/README.md index 895d4d9cda6c..39b2237112c8 100644 --- a/seed/go-sdk/openapi-path-param-body-collision/README.md +++ b/seed/go-sdk/openapi-path-param-body-collision/README.md @@ -72,7 +72,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.UpdateProfileIdentifier(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -94,7 +94,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -105,7 +104,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.UpdateProfileIdentifier( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/openapi-request-body-ref/no-custom-config/README.md b/seed/go-sdk/openapi-request-body-ref/no-custom-config/README.md index ec7d72e506f8..3a612d3f58df 100644 --- a/seed/go-sdk/openapi-request-body-ref/no-custom-config/README.md +++ b/seed/go-sdk/openapi-request-body-ref/no-custom-config/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Vendor.CreateVendor(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Vendor.CreateVendor( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/openapi-subtitle/README.md b/seed/go-sdk/openapi-subtitle/README.md index ae6af4d6ddea..4fefa14072ee 100644 --- a/seed/go-sdk/openapi-subtitle/README.md +++ b/seed/go-sdk/openapi-subtitle/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.ListPlants(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.ListPlants( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/optional/README.md b/seed/go-sdk/optional/README.md index cfbdc983c2da..39049b6a3ebb 100644 --- a/seed/go-sdk/optional/README.md +++ b/seed/go-sdk/optional/README.md @@ -69,7 +69,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Optional.SendOptionalBody(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -91,7 +91,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -102,7 +101,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Optional.SendOptionalBody( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/package-yml/no-custom-config/README.md b/seed/go-sdk/package-yml/no-custom-config/README.md index e11109d04e64..7c9e22174bc0 100644 --- a/seed/go-sdk/package-yml/no-custom-config/README.md +++ b/seed/go-sdk/package-yml/no-custom-config/README.md @@ -70,7 +70,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Echo(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -92,7 +92,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -103,7 +102,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Echo( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/pagination-custom/README.md b/seed/go-sdk/pagination-custom/README.md index f9edaf42941a..85ee89bd2caf 100644 --- a/seed/go-sdk/pagination-custom/README.md +++ b/seed/go-sdk/pagination-custom/README.md @@ -9,7 +9,6 @@ The Seed Go library provides convenient access to the Seed APIs from Go. - [Reference](#reference) - [Usage](#usage) - [Environments](#environments) -- [Pagination](#pagination) - [Errors](#errors) - [Request Options](#request-options) - [Advanced](#advanced) @@ -70,72 +69,6 @@ client := client.NewClient( ) ``` -## Pagination - -List endpoints are paginated. The SDK provides an iterator so that you can simply loop over the items. -You can also iterate page-by-page using the `GetNextPage` helper method. - -The `Page.Results` attribute, which contains the relevant list of items returned by the call to the server, -is the only attribute you will need for most use cases. But if need be, several other attributes are available: - -- `Page.Response` contains the full spec-defined response as returned by the server. -- `Page.StatusCode` and `Page.Header` returns HTTP metadata associated with the call to the server. -- `Page.RawResponse` returns the pagination object if you need to access its fields (like `Next`). - -```go -// Loop over the items using the provided iterator. -ctx := context.TODO() -page, err := client.Users.ListWithCustomPager( - ctx, - ... -) -if err != nil { - return err -} -iter := page.Iterator() -for iter.Next(ctx) { - item := iter.Current() - fmt.Printf("Got item: %v", *item) -} -if err := iter.Err(); err != nil { - return err -} - -// Alternatively, iterate page-by-page. -for page != nil { - for _, item := range page.Results { - fmt.Printf("Got item: %v", *item) - } - page, err = page.GetNextPage(ctx) - if errors.Is(err, core.ErrNoPages) { - break - } - if err != nil { - return err - } -} - -// Paginated endpoints return a Page with directly accessible headers, status code, and full response -ctx := context.TODO() -page, err := client.Users.ListWithCustomPager( - ctx, - ... -) -if err != nil { - return err -} - -// Access response metadata directly from the page -fmt.Printf("Got headers: %v", page.Header) -fmt.Printf("Got status code: %d", page.StatusCode) - -// Access the full spec-defined response object -fullResponse := page.Response - -// Access individual fields from the pagination object -nextCursor := page.RawResponse.Next -``` - ## Errors Structured error types are returned from API calls that return non-success status codes. These errors are compatible @@ -145,7 +78,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Users.ListWithCustomPager(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/pagination-uri-path/README.md b/seed/go-sdk/pagination-uri-path/README.md index 8ac953ad4dca..766d5f3f7acf 100644 --- a/seed/go-sdk/pagination-uri-path/README.md +++ b/seed/go-sdk/pagination-uri-path/README.md @@ -9,7 +9,6 @@ The Seed Go library provides convenient access to the Seed APIs from Go. - [Reference](#reference) - [Usage](#usage) - [Environments](#environments) -- [Pagination](#pagination) - [Errors](#errors) - [Request Options](#request-options) - [Advanced](#advanced) @@ -60,72 +59,6 @@ client := client.NewClient( ) ``` -## Pagination - -List endpoints are paginated. The SDK provides an iterator so that you can simply loop over the items. -You can also iterate page-by-page using the `GetNextPage` helper method. - -The `Page.Results` attribute, which contains the relevant list of items returned by the call to the server, -is the only attribute you will need for most use cases. But if need be, several other attributes are available: - -- `Page.Response` contains the full spec-defined response as returned by the server. -- `Page.StatusCode` and `Page.Header` returns HTTP metadata associated with the call to the server. -- `Page.RawResponse` returns the pagination object if you need to access its fields (like `Next`). - -```go -// Loop over the items using the provided iterator. -ctx := context.TODO() -page, err := client.Users.ListWithURIPagination( - ctx, - ... -) -if err != nil { - return err -} -iter := page.Iterator() -for iter.Next(ctx) { - item := iter.Current() - fmt.Printf("Got item: %v", *item) -} -if err := iter.Err(); err != nil { - return err -} - -// Alternatively, iterate page-by-page. -for page != nil { - for _, item := range page.Results { - fmt.Printf("Got item: %v", *item) - } - page, err = page.GetNextPage(ctx) - if errors.Is(err, core.ErrNoPages) { - break - } - if err != nil { - return err - } -} - -// Paginated endpoints return a Page with directly accessible headers, status code, and full response -ctx := context.TODO() -page, err := client.Users.ListWithURIPagination( - ctx, - ... -) -if err != nil { - return err -} - -// Access response metadata directly from the page -fmt.Printf("Got headers: %v", page.Header) -fmt.Printf("Got status code: %d", page.StatusCode) - -// Access the full spec-defined response object -fullResponse := page.Response - -// Access individual fields from the pagination object -nextCursor := page.RawResponse.Next -``` - ## Errors Structured error types are returned from API calls that return non-success status codes. These errors are compatible @@ -135,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Users.ListWithURIPagination(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/pagination/README.md b/seed/go-sdk/pagination/README.md index 15f546e68b19..8d6b1078f6fb 100644 --- a/seed/go-sdk/pagination/README.md +++ b/seed/go-sdk/pagination/README.md @@ -97,7 +97,7 @@ is the only attribute you will need for most use cases. But if need be, several ```go // Loop over the items using the provided iterator. ctx := context.TODO() -page, err := client.Complex.Search( +page, err := client.InlineUsers.InlineUsers.ListWithCursorPagination( ctx, ... ) @@ -128,8 +128,7 @@ for page != nil { } // Paginated endpoints return a Page with directly accessible headers, status code, and full response -ctx := context.TODO() -page, err := client.Complex.Search( +page, err = client.InlineUsers.InlineUsers.ListWithCursorPagination( ctx, ... ) @@ -157,7 +156,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Complex.Search(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/path-parameters/no-custom-config/README.md b/seed/go-sdk/path-parameters/no-custom-config/README.md index 097efe667ca3..397ded4ec334 100644 --- a/seed/go-sdk/path-parameters/no-custom-config/README.md +++ b/seed/go-sdk/path-parameters/no-custom-config/README.md @@ -73,7 +73,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.User.CreateUser(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -95,7 +95,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -106,7 +105,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.User.CreateUser( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/path-parameters/package-name/README.md b/seed/go-sdk/path-parameters/package-name/README.md index c5ada4124ec6..35eacc074c8b 100644 --- a/seed/go-sdk/path-parameters/package-name/README.md +++ b/seed/go-sdk/path-parameters/package-name/README.md @@ -73,7 +73,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.User.CreateUser(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -95,7 +95,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -106,7 +105,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.User.CreateUser( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/path-parameters/v0/README.md b/seed/go-sdk/path-parameters/v0/README.md index 097efe667ca3..397ded4ec334 100644 --- a/seed/go-sdk/path-parameters/v0/README.md +++ b/seed/go-sdk/path-parameters/v0/README.md @@ -73,7 +73,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.User.CreateUser(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -95,7 +95,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -106,7 +105,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.User.CreateUser( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/plain-text/README.md b/seed/go-sdk/plain-text/README.md index 521bb7de1183..b2523c074c2e 100644 --- a/seed/go-sdk/plain-text/README.md +++ b/seed/go-sdk/plain-text/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.GetText(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.GetText( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/property-access/README.md b/seed/go-sdk/property-access/README.md index 3a216154bf12..3a7ea298f153 100644 --- a/seed/go-sdk/property-access/README.md +++ b/seed/go-sdk/property-access/README.md @@ -77,7 +77,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.CreateUser(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -99,7 +99,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -110,7 +109,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.CreateUser( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/query-param-name-conflict/README.md b/seed/go-sdk/query-param-name-conflict/README.md index fab4a43cc949..c0aaa2dae0d3 100644 --- a/seed/go-sdk/query-param-name-conflict/README.md +++ b/seed/go-sdk/query-param-name-conflict/README.md @@ -66,7 +66,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.BulkUpdateTasks(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -88,7 +88,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -99,7 +98,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.BulkUpdateTasks( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/query-parameters-openapi-as-objects/README.md b/seed/go-sdk/query-parameters-openapi-as-objects/README.md index b544ce0bb68f..8e2f6c85c349 100644 --- a/seed/go-sdk/query-parameters-openapi-as-objects/README.md +++ b/seed/go-sdk/query-parameters-openapi-as-objects/README.md @@ -178,7 +178,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Search(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -200,7 +200,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -211,7 +210,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Search( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/query-parameters-openapi/README.md b/seed/go-sdk/query-parameters-openapi/README.md index 204cfea18630..d0c3dad25db5 100644 --- a/seed/go-sdk/query-parameters-openapi/README.md +++ b/seed/go-sdk/query-parameters-openapi/README.md @@ -178,7 +178,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Search(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -200,7 +200,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -211,7 +210,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Search( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/query-parameters/README.md b/seed/go-sdk/query-parameters/README.md index a85fc18fb7ad..e163fa381b66 100644 --- a/seed/go-sdk/query-parameters/README.md +++ b/seed/go-sdk/query-parameters/README.md @@ -142,7 +142,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.User.GetUsername(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -164,7 +164,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -175,7 +174,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.User.GetUsername( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/required-nullable/README.md b/seed/go-sdk/required-nullable/README.md index cc8ae075ae3e..3ec8022d5f56 100644 --- a/seed/go-sdk/required-nullable/README.md +++ b/seed/go-sdk/required-nullable/README.md @@ -71,7 +71,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.GetFoo(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -93,7 +93,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -104,7 +103,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.GetFoo( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/reserved-keywords/README.md b/seed/go-sdk/reserved-keywords/README.md index 75d42336433f..3024870339c4 100644 --- a/seed/go-sdk/reserved-keywords/README.md +++ b/seed/go-sdk/reserved-keywords/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Package.Test(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Package.Test( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/respect-optional-request-body/README.md b/seed/go-sdk/respect-optional-request-body/README.md index 3c05b1bff45b..051b7ba80970 100644 --- a/seed/go-sdk/respect-optional-request-body/README.md +++ b/seed/go-sdk/respect-optional-request-body/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Refund(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Refund( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/response-property/README.md b/seed/go-sdk/response-property/README.md index ff2240c7804d..aec7a05e38cc 100644 --- a/seed/go-sdk/response-property/README.md +++ b/seed/go-sdk/response-property/README.md @@ -65,7 +65,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.GetMovie(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -87,7 +87,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -98,7 +97,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.GetMovie( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/schemaless-request-body-examples/README.md b/seed/go-sdk/schemaless-request-body-examples/README.md index 3c933e70a432..d9b86efed9d3 100644 --- a/seed/go-sdk/schemaless-request-body-examples/README.md +++ b/seed/go-sdk/schemaless-request-body-examples/README.md @@ -77,7 +77,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.CreatePlant(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -99,7 +99,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -110,7 +109,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.CreatePlant( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/server-sent-event-examples/with-wire-tests/README.md b/seed/go-sdk/server-sent-event-examples/with-wire-tests/README.md index 7904c7661ccf..fea6f02044ed 100644 --- a/seed/go-sdk/server-sent-event-examples/with-wire-tests/README.md +++ b/seed/go-sdk/server-sent-event-examples/with-wire-tests/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Completions.Stream(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Completions.Stream( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/server-sent-events-openapi/with-wire-tests/README.md b/seed/go-sdk/server-sent-events-openapi/with-wire-tests/README.md index 07dae8470551..b06193e060e8 100644 --- a/seed/go-sdk/server-sent-events-openapi/with-wire-tests/README.md +++ b/seed/go-sdk/server-sent-events-openapi/with-wire-tests/README.md @@ -66,7 +66,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.StreamProtocolNoCollision(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -88,7 +88,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -99,7 +98,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.StreamProtocolNoCollision( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/server-sent-events-resumable/README.md b/seed/go-sdk/server-sent-events-resumable/README.md index 21d1dd84f3c0..a28285b17a79 100644 --- a/seed/go-sdk/server-sent-events-resumable/README.md +++ b/seed/go-sdk/server-sent-events-resumable/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Completions.Stream(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Completions.Stream( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/server-sent-events/with-wire-tests/README.md b/seed/go-sdk/server-sent-events/with-wire-tests/README.md index fc1687dd577f..cce6f21b8f2e 100644 --- a/seed/go-sdk/server-sent-events/with-wire-tests/README.md +++ b/seed/go-sdk/server-sent-events/with-wire-tests/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Completions.Stream(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Completions.Stream( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/server-url-templating-single-url/disable-server-url-variables/README.md b/seed/go-sdk/server-url-templating-single-url/disable-server-url-variables/README.md index 3bcb0f961739..488686d2483a 100644 --- a/seed/go-sdk/server-url-templating-single-url/disable-server-url-variables/README.md +++ b/seed/go-sdk/server-url-templating-single-url/disable-server-url-variables/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.GetUsers(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.GetUsers( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/server-url-templating-single-url/no-custom-config/README.md b/seed/go-sdk/server-url-templating-single-url/no-custom-config/README.md index 3bcb0f961739..488686d2483a 100644 --- a/seed/go-sdk/server-url-templating-single-url/no-custom-config/README.md +++ b/seed/go-sdk/server-url-templating-single-url/no-custom-config/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.GetUsers(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.GetUsers( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/server-url-templating/disable-server-url-variables/README.md b/seed/go-sdk/server-url-templating/disable-server-url-variables/README.md index f668172a8897..7fb2286147ad 100644 --- a/seed/go-sdk/server-url-templating/disable-server-url-variables/README.md +++ b/seed/go-sdk/server-url-templating/disable-server-url-variables/README.md @@ -69,7 +69,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.GetToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -91,7 +91,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -102,7 +101,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.GetToken( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/server-url-templating/no-custom-config/README.md b/seed/go-sdk/server-url-templating/no-custom-config/README.md index f668172a8897..7fb2286147ad 100644 --- a/seed/go-sdk/server-url-templating/no-custom-config/README.md +++ b/seed/go-sdk/server-url-templating/no-custom-config/README.md @@ -69,7 +69,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.GetToken(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -91,7 +91,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -102,7 +101,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.GetToken( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/simple-api/README.md b/seed/go-sdk/simple-api/README.md index a78e1d57807d..5c55dc135acb 100644 --- a/seed/go-sdk/simple-api/README.md +++ b/seed/go-sdk/simple-api/README.md @@ -69,7 +69,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.User.Get(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/simple-fhir/README.md b/seed/go-sdk/simple-fhir/README.md index bc9c2ff165fc..aad4aad697a3 100644 --- a/seed/go-sdk/simple-fhir/README.md +++ b/seed/go-sdk/simple-fhir/README.md @@ -64,7 +64,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.GetAccount(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -86,7 +86,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -97,7 +96,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.GetAccount( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/single-url-environment-default/README.md b/seed/go-sdk/single-url-environment-default/README.md index 63ce5cef5a9a..f57e85b590b6 100644 --- a/seed/go-sdk/single-url-environment-default/README.md +++ b/seed/go-sdk/single-url-environment-default/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Dummy.GetDummy(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/single-url-environment-no-default/README.md b/seed/go-sdk/single-url-environment-no-default/README.md index d0ced3004b1e..30dd94155658 100644 --- a/seed/go-sdk/single-url-environment-no-default/README.md +++ b/seed/go-sdk/single-url-environment-no-default/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Dummy.GetDummy(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/streaming-parameter/README.md b/seed/go-sdk/streaming-parameter/README.md index e903ce2638a6..66178e1d9e02 100644 --- a/seed/go-sdk/streaming-parameter/README.md +++ b/seed/go-sdk/streaming-parameter/README.md @@ -69,7 +69,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Dummy.Generate(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -91,7 +91,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -102,7 +101,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Dummy.Generate( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/streaming/README.md b/seed/go-sdk/streaming/README.md index fae084c2efe7..0b3c3c02b2e2 100644 --- a/seed/go-sdk/streaming/README.md +++ b/seed/go-sdk/streaming/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Dummy.GenerateStream(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Dummy.GenerateStream( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/trace/README.md b/seed/go-sdk/trace/README.md index 7e5cd825c22c..bd172a2a6ab4 100644 --- a/seed/go-sdk/trace/README.md +++ b/seed/go-sdk/trace/README.md @@ -77,7 +77,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Admin.UpdateTestSubmissionStatus(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err diff --git a/seed/go-sdk/undiscriminated-union-with-response-property/README.md b/seed/go-sdk/undiscriminated-union-with-response-property/README.md index 986c14bcd909..6af7ae7a69f6 100644 --- a/seed/go-sdk/undiscriminated-union-with-response-property/README.md +++ b/seed/go-sdk/undiscriminated-union-with-response-property/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.GetUnion(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.GetUnion( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/README.md b/seed/go-sdk/undiscriminated-unions/no-custom-config/README.md index a96744f49c07..259a97568401 100644 --- a/seed/go-sdk/undiscriminated-unions/no-custom-config/README.md +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Union.Get(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Union.Get( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/undiscriminated-unions/v0/README.md b/seed/go-sdk/undiscriminated-unions/v0/README.md index 4bc8532bff08..caa03ccdcf27 100644 --- a/seed/go-sdk/undiscriminated-unions/v0/README.md +++ b/seed/go-sdk/undiscriminated-unions/v0/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Union.Get(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Union.Get( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/union-query-parameters/README.md b/seed/go-sdk/union-query-parameters/README.md index fbb303b59c88..1dda7aa0acc5 100644 --- a/seed/go-sdk/union-query-parameters/README.md +++ b/seed/go-sdk/union-query-parameters/README.md @@ -73,7 +73,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Events.Subscribe(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -95,7 +95,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -106,7 +105,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Events.Subscribe( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/unions-with-local-date/README.md b/seed/go-sdk/unions-with-local-date/README.md index 07ccfd019cb6..e235bcda8f5d 100644 --- a/seed/go-sdk/unions-with-local-date/README.md +++ b/seed/go-sdk/unions-with-local-date/README.md @@ -64,7 +64,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Bigunion.Get(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -86,7 +86,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -97,7 +96,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Bigunion.Get( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/unions/no-custom-config/README.md b/seed/go-sdk/unions/no-custom-config/README.md index fcaec5e89ab7..ba0f704b1fde 100644 --- a/seed/go-sdk/unions/no-custom-config/README.md +++ b/seed/go-sdk/unions/no-custom-config/README.md @@ -64,7 +64,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Bigunion.Get(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -86,7 +86,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -97,7 +96,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Bigunion.Get( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/unions/package-name/README.md b/seed/go-sdk/unions/package-name/README.md index 1ec466435c13..6d3d4153941e 100644 --- a/seed/go-sdk/unions/package-name/README.md +++ b/seed/go-sdk/unions/package-name/README.md @@ -64,7 +64,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Bigunion.Get(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -86,7 +86,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -97,7 +96,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Bigunion.Get( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/unions/v0/README.md b/seed/go-sdk/unions/v0/README.md index fcaec5e89ab7..ba0f704b1fde 100644 --- a/seed/go-sdk/unions/v0/README.md +++ b/seed/go-sdk/unions/v0/README.md @@ -64,7 +64,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Bigunion.Get(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -86,7 +86,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -97,7 +96,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Bigunion.Get( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/unknown/README.md b/seed/go-sdk/unknown/README.md index f9b292d37e42..060a9f2ae412 100644 --- a/seed/go-sdk/unknown/README.md +++ b/seed/go-sdk/unknown/README.md @@ -67,7 +67,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Unknown.Post(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -89,7 +89,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -100,7 +99,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Unknown.Post( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/url-form-encoded/README.md b/seed/go-sdk/url-form-encoded/README.md index 26e948e08377..51d4d2fe4735 100644 --- a/seed/go-sdk/url-form-encoded/README.md +++ b/seed/go-sdk/url-form-encoded/README.md @@ -69,7 +69,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.SubmitFormData(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -91,7 +91,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -102,7 +101,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.SubmitFormData( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/validation/README.md b/seed/go-sdk/validation/README.md index 31eec82cbe84..7eced34cadc2 100644 --- a/seed/go-sdk/validation/README.md +++ b/seed/go-sdk/validation/README.md @@ -71,7 +71,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Create(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -93,7 +93,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -104,7 +103,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Create( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/variables/README.md b/seed/go-sdk/variables/README.md index 119358f1deba..cdf9d61de9db 100644 --- a/seed/go-sdk/variables/README.md +++ b/seed/go-sdk/variables/README.md @@ -64,7 +64,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Service.Post(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -86,7 +86,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -97,7 +96,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Service.Post( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/version-no-default/README.md b/seed/go-sdk/version-no-default/README.md index 19168bb827eb..00ad345b5bf0 100644 --- a/seed/go-sdk/version-no-default/README.md +++ b/seed/go-sdk/version-no-default/README.md @@ -64,7 +64,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.User.GetUser(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -86,7 +86,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -97,7 +96,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.User.GetUser( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/version/README.md b/seed/go-sdk/version/README.md index f40c493f237e..3a83c96a9188 100644 --- a/seed/go-sdk/version/README.md +++ b/seed/go-sdk/version/README.md @@ -64,7 +64,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.User.GetUser(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -86,7 +86,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -97,7 +96,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.User.GetUser( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/websocket-inferred-auth/README.md b/seed/go-sdk/websocket-inferred-auth/README.md index 9a66ec44886f..7e4001167d42 100644 --- a/seed/go-sdk/websocket-inferred-auth/README.md +++ b/seed/go-sdk/websocket-inferred-auth/README.md @@ -84,7 +84,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Auth.GetTokenWithClientCredentials(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -106,7 +106,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -117,7 +116,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Auth.GetTokenWithClientCredentials( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/websocket/README.md b/seed/go-sdk/websocket/README.md index 77930a7ef4e5..1941f68f5480 100644 --- a/seed/go-sdk/websocket/README.md +++ b/seed/go-sdk/websocket/README.md @@ -63,7 +63,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Status.GetStatus(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -85,7 +85,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -96,7 +95,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Status.GetStatus( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/x-fern-default/apply-query-defaults-on-nil-request/README.md b/seed/go-sdk/x-fern-default/apply-query-defaults-on-nil-request/README.md index 2300969b9b9b..1823934aad1f 100644 --- a/seed/go-sdk/x-fern-default/apply-query-defaults-on-nil-request/README.md +++ b/seed/go-sdk/x-fern-default/apply-query-defaults-on-nil-request/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.TestGet(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.TestGet( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/x-fern-default/no-custom-config/README.md b/seed/go-sdk/x-fern-default/no-custom-config/README.md index 2300969b9b9b..1823934aad1f 100644 --- a/seed/go-sdk/x-fern-default/no-custom-config/README.md +++ b/seed/go-sdk/x-fern-default/no-custom-config/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.TestGet(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.TestGet( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` diff --git a/seed/go-sdk/x-fern-global-parameters/README.md b/seed/go-sdk/x-fern-global-parameters/README.md index 0bfc6f13aa69..d258f21dc108 100644 --- a/seed/go-sdk/x-fern-global-parameters/README.md +++ b/seed/go-sdk/x-fern-global-parameters/README.md @@ -68,7 +68,7 @@ with the `errors.Is` and `errors.As` APIs, so you can access the error like so: response, err := client.Products.Search(...) if err != nil { var apiError *core.APIError - if errors.As(err, apiError) { + if errors.As(err, &apiError) { // Do something with the API error ... } return err @@ -90,7 +90,6 @@ specified on the client so that they're applied on every request, or for an indi ```go // Specify default options applied on every request. client := client.NewClient( - option.WithToken(""), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -101,7 +100,7 @@ client := client.NewClient( // Specify options for an individual request. response, err := client.Products.Search( ..., - option.WithToken(""), + option.WithMaxAttempts(1), ) ``` From cd79a927b12a42465782bf5dea043841ebdc05a0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 20 Aug 2026 14:45:53 +0000 Subject: [PATCH 5/7] chore(go): release 1.57.4 --- .../fix-readme-snippets.yml | 0 generators/go/sdk/versions.yml | 20 +++++++++++++++++++ 2 files changed, 20 insertions(+) rename generators/go/sdk/changes/{unreleased => 1.57.4}/fix-readme-snippets.yml (100%) diff --git a/generators/go/sdk/changes/unreleased/fix-readme-snippets.yml b/generators/go/sdk/changes/1.57.4/fix-readme-snippets.yml similarity index 100% rename from generators/go/sdk/changes/unreleased/fix-readme-snippets.yml rename to generators/go/sdk/changes/1.57.4/fix-readme-snippets.yml diff --git a/generators/go/sdk/versions.yml b/generators/go/sdk/versions.yml index 2b7ef5d4a6cd..8299c4fbd566 100644 --- a/generators/go/sdk/versions.yml +++ b/generators/go/sdk/versions.yml @@ -1,4 +1,24 @@ # yaml-language-server: $schema=../../../fern-versions-yml.schema.json +- version: 1.57.4 + changelogEntry: + - summary: | + Fix several issues in the generated README: + - The Request Options example now renders the auth options the SDK actually + generates (e.g., `option.WithSecret` for header auth, `option.WithBasicAuth` + for basic auth) instead of always assuming `option.WithToken`. + - The Errors example now passes a pointer to `errors.As` so the snippet + compiles and doesn't panic. + - The Pagination section is now emitted whenever the API has an endpoint + with a generated paginated client, by selecting such an endpoint for the + example, rather than relying on the default endpoint being paginated. The + section is omitted entirely when no paginated client is generated (e.g. + custom, URI, and path pagination), so the example no longer references an + iterator that doesn't exist. + - The Request Options section now documents the environment variables the + generated client reads credentials from when they aren't explicitly provided. + type: fix + createdAt: "2026-08-20" + irVersion: 67 - version: 1.57.3 changelogEntry: - summary: | From c1b8818742648fcc06842654f6aab5637f3e9f8d Mon Sep 17 00:00:00 2001 From: Barrett Jones Date: Thu, 20 Aug 2026 11:10:30 -0500 Subject: [PATCH 6/7] feat(cli): add default-disabled sdk-gen-api generation backend (#17478) --- packages/cli/cli/build.dev.mjs | 2 + packages/cli/cli/build.local.mjs | 2 + packages/cli/cli/build.prod-unminified.mjs | 2 + packages/cli/cli/build.prod.mjs | 2 + .../unreleased/sdk-gen-api-backend.yml | 7 + .../__test__/createSpecsTarGzCache.test.ts | 23 + .../generate/createSpecsTarGzCache.ts | 12 + .../commands/generate/generateAPIWorkspace.ts | 33 +- .../local-workspace-runner/src/rawSpecs.ts | 2 +- .../src/RemoteTaskHandler.ts | 12 +- .../src/__test__/fernSdkGenApi.test.ts | 502 ++++++++++ .../src/fernSdkGenApi.ts | 895 ++++++++++++++++++ .../remote-workspace-runner/src/index.ts | 1 + .../src/runRemoteGenerationForAPIWorkspace.ts | 21 +- .../src/runRemoteGenerationForGenerator.ts | 220 +++-- 15 files changed, 1646 insertions(+), 90 deletions(-) create mode 100644 packages/cli/cli/changes/unreleased/sdk-gen-api-backend.yml create mode 100644 packages/cli/cli/src/commands/generate/__test__/createSpecsTarGzCache.test.ts create mode 100644 packages/cli/cli/src/commands/generate/createSpecsTarGzCache.ts create mode 100644 packages/cli/generation/remote-generation/remote-workspace-runner/src/__test__/fernSdkGenApi.test.ts create mode 100644 packages/cli/generation/remote-generation/remote-workspace-runner/src/fernSdkGenApi.ts diff --git a/packages/cli/cli/build.dev.mjs b/packages/cli/cli/build.dev.mjs index 4c4d88164da7..b2a02ae5471f 100644 --- a/packages/cli/cli/build.dev.mjs +++ b/packages/cli/cli/build.dev.mjs @@ -7,6 +7,8 @@ buildCli({ AUTH0_DOMAIN: "fern-dev.us.auth0.com", AUTH0_CLIENT_ID: "4QiMvRvRUYpnycrVDK2M59hhJ6kcHYFQ", DEFAULT_FIDDLE_ORIGIN: "https://fiddle-coordinator-dev2.buildwithfern.com", + DEFAULT_SDK_GEN_API_ORIGIN: "https://sdk-gen.postman-beta.tech", + DEFAULT_USE_SDK_GEN_API: "false", DEFAULT_VENUS_ORIGIN: "https://venus-dev2.buildwithfern.com", DEFAULT_FDR_ORIGIN: "https://registry-dev2.buildwithfern.com", DEFAULT_FAI_ORIGIN: "https://fai-dev2.buildwithfern.com", diff --git a/packages/cli/cli/build.local.mjs b/packages/cli/cli/build.local.mjs index 0bb5a9a4758b..74bf5f69130e 100644 --- a/packages/cli/cli/build.local.mjs +++ b/packages/cli/cli/build.local.mjs @@ -7,6 +7,8 @@ buildCli({ AUTH0_DOMAIN: "localhost:3100", AUTH0_CLIENT_ID: "fern", DEFAULT_FIDDLE_ORIGIN: "https://fiddle-coordinator-dev2.buildwithfern.com", + DEFAULT_SDK_GEN_API_ORIGIN: "http://localhost:3001", + DEFAULT_USE_SDK_GEN_API: "false", DEFAULT_VENUS_ORIGIN: "http://localhost:8089", DEFAULT_FDR_ORIGIN: "http://localhost:8080", FERN_FDR_ORIGIN: "http://localhost:8080", diff --git a/packages/cli/cli/build.prod-unminified.mjs b/packages/cli/cli/build.prod-unminified.mjs index 2266ac12d1ce..9e91d5f15fa1 100644 --- a/packages/cli/cli/build.prod-unminified.mjs +++ b/packages/cli/cli/build.prod-unminified.mjs @@ -7,6 +7,8 @@ buildCli({ AUTH0_DOMAIN: "fern-prod.us.auth0.com", AUTH0_CLIENT_ID: "syaWnk6SjNoo5xBf1omfvziU3q7085lh", DEFAULT_FIDDLE_ORIGIN: "https://fiddle-coordinator.buildwithfern.com", + DEFAULT_SDK_GEN_API_ORIGIN: "https://sdk-gen.postman.co", + DEFAULT_USE_SDK_GEN_API: "false", DEFAULT_VENUS_ORIGIN: "https://venus.buildwithfern.com", DEFAULT_FDR_ORIGIN: "https://registry.buildwithfern.com", VENUS_AUDIENCE: "venus-prod", diff --git a/packages/cli/cli/build.prod.mjs b/packages/cli/cli/build.prod.mjs index 06604542d73c..f9e8334e87ef 100644 --- a/packages/cli/cli/build.prod.mjs +++ b/packages/cli/cli/build.prod.mjs @@ -7,6 +7,8 @@ buildCli({ AUTH0_DOMAIN: "fern-prod.us.auth0.com", AUTH0_CLIENT_ID: "syaWnk6SjNoo5xBf1omfvziU3q7085lh", DEFAULT_FIDDLE_ORIGIN: "https://fiddle-coordinator.buildwithfern.com", + DEFAULT_SDK_GEN_API_ORIGIN: "https://sdk-gen.postman.co", + DEFAULT_USE_SDK_GEN_API: "false", DEFAULT_VENUS_ORIGIN: "https://venus.buildwithfern.com", DEFAULT_FDR_ORIGIN: "https://registry.buildwithfern.com", DEFAULT_FAI_ORIGIN: "https://fai.buildwithfern.com", diff --git a/packages/cli/cli/changes/unreleased/sdk-gen-api-backend.yml b/packages/cli/cli/changes/unreleased/sdk-gen-api-backend.yml new file mode 100644 index 000000000000..01c1bf638dbf --- /dev/null +++ b/packages/cli/cli/changes/unreleased/sdk-gen-api-backend.yml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json + +- summary: | + Add an internal, default-disabled SDK generation route through sdk-gen-api. Preserve local + generation and non-SDK remote generators on their existing paths, and report unsupported + SDK migration features explicitly instead of silently falling back to Fiddle. + type: internal diff --git a/packages/cli/cli/src/commands/generate/__test__/createSpecsTarGzCache.test.ts b/packages/cli/cli/src/commands/generate/__test__/createSpecsTarGzCache.test.ts new file mode 100644 index 000000000000..37cfb6afd522 --- /dev/null +++ b/packages/cli/cli/src/commands/generate/__test__/createSpecsTarGzCache.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it, vi } from "vitest"; +import { createSpecsTarGzCache } from "../createSpecsTarGzCache.js"; + +describe("createSpecsTarGzCache", () => { + it("shares one in-flight archive operation with concurrent generator tasks", async () => { + let resolveArchive: ((archive: Buffer) => void) | undefined; + const deferredArchive = new Promise((resolve) => { + resolveArchive = resolve; + }); + const archiveFactory = vi.fn(() => deferredArchive); + const getArchive = createSpecsTarGzCache(archiveFactory); + + const archiveRequests = [getArchive(), getArchive(), getArchive(), getArchive()]; + + expect(archiveFactory).toHaveBeenCalledTimes(1); + const archive = Buffer.from("shared-specs-archive"); + resolveArchive?.(archive); + + const results = await Promise.all(archiveRequests); + expect(results).toEqual([archive, archive, archive, archive]); + expect(results.every((result) => result === archive)).toBe(true); + }); +}); diff --git a/packages/cli/cli/src/commands/generate/createSpecsTarGzCache.ts b/packages/cli/cli/src/commands/generate/createSpecsTarGzCache.ts new file mode 100644 index 000000000000..4d43fb9edc39 --- /dev/null +++ b/packages/cli/cli/src/commands/generate/createSpecsTarGzCache.ts @@ -0,0 +1,12 @@ +/** + * Memoizes both the in-flight archive operation and its result. Concurrent generator tasks must + * await the same promise; caching only a completion boolean allows siblings to observe an empty + * result while the first archive is still being built. + */ +export function createSpecsTarGzCache(createArchive: () => Promise): () => Promise { + let archivePromise: Promise | undefined; + return () => { + archivePromise ??= createArchive(); + return archivePromise; + }; +} diff --git a/packages/cli/cli/src/commands/generate/generateAPIWorkspace.ts b/packages/cli/cli/src/commands/generate/generateAPIWorkspace.ts index 6a027dacb338..42def2513c6e 100644 --- a/packages/cli/cli/src/commands/generate/generateAPIWorkspace.ts +++ b/packages/cli/cli/src/commands/generate/generateAPIWorkspace.ts @@ -12,7 +12,9 @@ import { AutomationRunOptions, findGeneratorLineNumber, GeneratorOccurrenceTracker, + getFernSdkGenApiLanguage, getOutputRepoUrl, + isFernSdkGenApiEnabled, runRemoteGenerationForAPIWorkspace } from "@fern-api/remote-workspace-runner"; import { CliError, TaskContext } from "@fern-api/task-context"; @@ -20,6 +22,7 @@ import { AbstractAPIWorkspace } from "@fern-api/workspace-loader"; import { FernFiddle } from "@fern-fern/fiddle-sdk"; import { isTelemetryDisabled } from "../../telemetry/isTelemetryDisabled.js"; +import { createSpecsTarGzCache } from "./createSpecsTarGzCache.js"; import { filterGenerators } from "./filterGenerators.js"; import { GenerationMode } from "./generateAPIWorkspaces.js"; import { PackMode, packLocalOutputForGroup } from "./packLocalOutput.js"; @@ -193,21 +196,27 @@ export async function generateWorkspace({ }); } else if (token != null) { // Lazily build the specs tar.gz once per group, only if a generator needs it - let cachedSpecsTarGz: Buffer | undefined; - let specsComputed = false; + const ossWorkspace = workspace instanceof OSSWorkspace ? workspace : undefined; + const getCachedSpecsTarGz = + ossWorkspace == null + ? undefined + : createSpecsTarGzCache(() => + createSpecsTarGzBuffer({ + specs: ossWorkspace.allSpecs, + context: groupContext, + audiences: group.audiences + }) + ); const getSpecsTarGz = async (generatorName: string): Promise => { - if (!(workspace instanceof OSSWorkspace) || !generatorWantsSpecs(generatorName)) { + const sdkGenApiNeedsSpecs = + isFernSdkGenApiEnabled() && getFernSdkGenApiLanguage(generatorName) != null; + if ( + getCachedSpecsTarGz == null || + (!generatorWantsSpecs(generatorName) && !sdkGenApiNeedsSpecs) + ) { return undefined; } - if (!specsComputed) { - specsComputed = true; - cachedSpecsTarGz = await createSpecsTarGzBuffer({ - specs: workspace.allSpecs, - context: groupContext, - audiences: group.audiences - }); - } - return cachedSpecsTarGz; + return getCachedSpecsTarGz(); }; await runRemoteGenerationForAPIWorkspace({ diff --git a/packages/cli/generation/local-generation/local-workspace-runner/src/rawSpecs.ts b/packages/cli/generation/local-generation/local-workspace-runner/src/rawSpecs.ts index 2afc0c07a670..a5afc17cbeac 100644 --- a/packages/cli/generation/local-generation/local-workspace-runner/src/rawSpecs.ts +++ b/packages/cli/generation/local-generation/local-workspace-runner/src/rawSpecs.ts @@ -432,7 +432,7 @@ function hasOperations(pathItem: Record): boolean { /** * Collects raw API specs, writes them to a temporary directory alongside a * manifest, and packages everything into a gzipped tar archive suitable for - * uploading to Fiddle's `startJob` endpoint. + * remote generation backends. */ export async function createSpecsTarGzBuffer({ specs, diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/RemoteTaskHandler.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/RemoteTaskHandler.ts index 8246abc3cf6f..fa91f02c018f 100644 --- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/RemoteTaskHandler.ts +++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/RemoteTaskHandler.ts @@ -442,26 +442,28 @@ function extractGithubModeFromGenerator( return "push"; } -async function downloadFilesForTask({ +export async function downloadFilesForTask({ s3PreSignedReadUrl, absolutePathToLocalOutput, - context + context, + skipFernignore = false }: { s3PreSignedReadUrl: string; absolutePathToLocalOutput: AbsoluteFilePath; context: InteractiveTaskContext; -}) { + skipFernignore?: boolean; +}): Promise { try { const isFernIgnorePresent = await checkFernIgnorePresent(absolutePathToLocalOutput); const isExistingGitRepo = await checkIsGitRepository(absolutePathToLocalOutput); - if (isFernIgnorePresent && isExistingGitRepo) { + if (!skipFernignore && isFernIgnorePresent && isExistingGitRepo) { await downloadFilesWithFernIgnoreInExistingRepo({ s3PreSignedReadUrl, absolutePathToLocalOutput, context }); - } else if (isFernIgnorePresent && !isExistingGitRepo) { + } else if (!skipFernignore && isFernIgnorePresent && !isExistingGitRepo) { await downloadFilesWithFernIgnoreInTempRepo({ s3PreSignedReadUrl, absolutePathToLocalOutput, diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/__test__/fernSdkGenApi.test.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/__test__/fernSdkGenApi.test.ts new file mode 100644 index 000000000000..d3ef401ff238 --- /dev/null +++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/__test__/fernSdkGenApi.test.ts @@ -0,0 +1,502 @@ +import { generatorsYml } from "@fern-api/configuration"; +import { FernFiddle } from "@fern-fern/fiddle-sdk"; +import axios from "axios"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { + createFernSdkGenApiBatchRequest, + createFernSdkGenApiRequest, + FernSdkGenApiBatch, + getFernSdkGenApiLanguage, + getFernSdkGenApiOrigin, + isEligibleForFernSdkGenApi, + isFernSdkGenApiEnabled, + runFernSdkGenApiBuild +} from "../fernSdkGenApi.js"; + +afterEach(() => { + vi.restoreAllMocks(); + vi.unstubAllEnvs(); +}); + +function invocation(overrides: Record = {}): generatorsYml.GeneratorInvocation { + return { + name: "fernapi/fern-typescript-sdk", + version: "3.86.0", + language: "typescript", + config: {}, + keywords: [], + smartCasing: true, + smartCasingDigitWordBoundary: false, + disableExamples: false, + outputMode: { type: "downloadFiles" }, + ...overrides + } as unknown as generatorsYml.GeneratorInvocation; +} + +describe("isEligibleForFernSdkGenApi", () => { + it("selects first-party SDK generators in every supported language", () => { + const generators = [ + ["fernapi/fern-typescript-sdk", "typescript"], + ["fernapi/fern-python-sdk", "python"], + ["fernapi/fern-java-sdk", "java"], + ["fernapi/fern-kotlin-sdk", "kotlin"], + ["fernapi/fern-go-sdk", "go"], + ["fernapi/fern-csharp-sdk", "csharp"], + ["fernapi/fern-php-sdk", "php"], + ["fernapi/fern-ruby-sdk", "ruby"], + ["fernapi/fern-rust-sdk", "rust"], + ["fernapi/fern-swift-sdk", "swift"], + ["fernapi/fern-cli-generator", "cli"] + ] as const; + + for (const [name, language] of generators) { + expect(getFernSdkGenApiLanguage(name)).toBe(language); + expect( + isEligibleForFernSdkGenApi({ + generatorInvocation: invocation({ name, language }), + sdkVersion: "1.2.3", + specsTarGzBuffer: Buffer.from("archive") + }) + ).toBe(true); + } + }); + + it("retains configured invocations on the sdk-gen-api route", () => { + expect( + isEligibleForFernSdkGenApi({ + generatorInvocation: invocation({ + config: { packageJson: { name: "@acme/sdk" } } + }), + sdkVersion: "1.2.3", + specsTarGzBuffer: Buffer.from("archive") + }) + ).toBe(true); + }); + + it("rejects non-SDK generators and unresolved SDK versions", () => { + expect( + isEligibleForFernSdkGenApi({ + generatorInvocation: invocation({ + name: "fernapi/fern-typescript-express" + }), + sdkVersion: "1.2.3", + specsTarGzBuffer: Buffer.from("archive") + }) + ).toBe(false); + expect( + isEligibleForFernSdkGenApi({ + generatorInvocation: invocation(), + sdkVersion: undefined, + specsTarGzBuffer: Buffer.from("archive") + }) + ).toBe(false); + }); + + it("routes GitHub and registry output through sdk-gen-api", () => { + const outputs = [ + FernFiddle.OutputMode.githubV2( + FernFiddle.GithubOutputModeV2.push({ + owner: "acme", + repo: "sdk", + branch: "main" + }) + ), + FernFiddle.OutputMode.publishV2( + FernFiddle.PublishOutputModeV2.npmOverride({ + registryUrl: "https://registry.npmjs.org", + packageName: "@acme/sdk", + token: "secret" + }) + ) + ]; + + for (const outputMode of outputs) { + expect( + isEligibleForFernSdkGenApi({ + generatorInvocation: invocation({ outputMode }), + sdkVersion: "1.2.3", + specsTarGzBuffer: Buffer.from("archive") + }) + ).toBe(true); + } + }); + + it("rejects AUTO until the shared pipeline owns Fern's post-generation version replacement", () => { + expect( + isEligibleForFernSdkGenApi({ + generatorInvocation: invocation(), + sdkVersion: "AUTO", + specsTarGzBuffer: Buffer.from("archive") + }) + ).toBe(false); + }); + + it("rejects whitelabel builds until the shared pipeline can preserve their branding behavior", () => { + expect( + isEligibleForFernSdkGenApi({ + generatorInvocation: invocation(), + sdkVersion: "1.2.3", + specsTarGzBuffer: Buffer.from("archive"), + whitelabel: { + github: { token: "token", username: "fern", email: "fern@example.com" } + } + }) + ).toBe(false); + }); + + it("references every source in the uploaded archive", () => { + const request = createFernSdkGenApiRequest({ + apiName: "Petstore", + organization: "acme", + cliVersion: "0.0.0", + generatorInvocation: invocation(), + sdkVersion: "1.2.3", + specsTarGzBuffer: Buffer.from("archive") + }); + + expect(request.apiInputs).toEqual([{ id: "default", specIndexes: "all" }]); + expect(request.targets[0]).toMatchObject({ + language: "typescript", + invocation: { + customConfig: {}, + keywords: [], + smartCasing: true, + smartCasingDigitWordBoundary: false, + disableExamples: false + } + }); + expect(request.targets[0]?.invocation).not.toHaveProperty("audiences"); + }); + + it("preserves an explicitly selected audience list", () => { + const request = createFernSdkGenApiBatchRequest({ + apiName: "Petstore", + organization: "acme", + cliVersion: "0.0.0", + specsTarGzBuffer: Buffer.from("archive"), + targets: [ + { + generatorInvocation: invocation(), + sdkVersion: "1.2.3", + audiences: ["public"] + } + ] + }); + + expect(request.targets[0]?.invocation.audiences).toEqual(["public"]); + }); + + it("uses the generator language instead of hard-coding TypeScript", () => { + const request = createFernSdkGenApiRequest({ + apiName: "Petstore", + organization: "acme", + cliVersion: "0.0.0", + generatorInvocation: invocation({ + name: "fernapi/fern-python-sdk", + language: "python", + version: "4.64.1" + }), + sdkVersion: "1.2.3", + specsTarGzBuffer: Buffer.from("archive") + }); + + expect(request.targets[0]?.language).toBe("python"); + }); + + it("maps GitHub delivery and optional registry publication", () => { + const request = createFernSdkGenApiRequest({ + apiName: "Petstore", + organization: "acme", + cliVersion: "0.0.0", + generatorInvocation: invocation({ + outputMode: FernFiddle.OutputMode.githubV2( + FernFiddle.GithubOutputModeV2.pullRequest({ + owner: "acme", + repo: "typescript-sdk", + host: "github.example.com", + branch: "develop", + reviewers: [ + FernFiddle.GithubPullRequestReviewer.team({ + name: "sdk-reviewers" + }), + FernFiddle.GithubPullRequestReviewer.user({ name: "octocat" }) + ], + publishInfo: FernFiddle.GithubPublishInfo.npm({ + registryUrl: "https://registry.npmjs.org", + packageName: "@acme/typescript-sdk" + }) + }) + ) + }), + sdkVersion: "1.2.3", + specsTarGzBuffer: Buffer.from("archive") + }); + + expect(request.targets[0]).toMatchObject({ + package: { packageName: "@acme/typescript-sdk" }, + requestedOutput: { + type: "github", + repository: "acme/typescript-sdk", + host: "github.example.com", + branch: "develop", + mode: "pull-request", + reviewers: { teams: ["sdk-reviewers"], users: ["octocat"] }, + publish: { registry: "npm", url: "https://registry.npmjs.org" } + } + }); + expect(JSON.stringify(request)).not.toContain("secret"); + }); + + it("maps direct registry publication and package identity", () => { + const request = createFernSdkGenApiRequest({ + apiName: "Petstore", + organization: "acme", + cliVersion: "0.0.0", + generatorInvocation: invocation({ + name: "fernapi/fern-python-sdk", + language: "python", + outputMode: FernFiddle.OutputMode.publishV2( + FernFiddle.PublishOutputModeV2.pypiOverride({ + registryUrl: "https://upload.pypi.org/legacy/", + coordinate: "acme-sdk", + username: "__token__", + password: "secret" + }) + ) + }), + sdkVersion: "1.2.3", + specsTarGzBuffer: Buffer.from("archive") + }); + + expect(request.targets[0]).toMatchObject({ + package: { packageName: "acme-sdk" }, + requestedOutput: { + type: "publish", + publish: { registry: "pypi", url: "https://upload.pypi.org/legacy/" } + } + }); + expect(JSON.stringify(request)).not.toContain("secret"); + }); + + it("creates one request for a group with multiple languages and duplicate-language targets", () => { + const request = createFernSdkGenApiBatchRequest({ + apiName: "Petstore", + organization: "acme", + cliVersion: "0.0.0", + specsTarGzBuffer: Buffer.from("archive"), + targets: [ + { + generatorInvocation: invocation(), + sdkVersion: "1.2.3", + targetIdSeed: "0" + }, + { + generatorInvocation: invocation({ + name: "fernapi/fern-python-sdk", + language: "python", + version: "4.64.1" + }), + sdkVersion: "1.2.3", + targetIdSeed: "1" + }, + { + generatorInvocation: invocation(), + sdkVersion: "2.0.0", + targetIdSeed: "2" + } + ] + }); + + expect(request.targets.map((target) => target.language)).toEqual(["typescript", "python", "typescript"]); + expect(new Set(request.targets.map((target) => target.targetId)).size).toBe(3); + }); + + it("changes the idempotency key when generator configuration or output changes", () => { + const createRequest = (generatorInvocation: generatorsYml.GeneratorInvocation) => + createFernSdkGenApiRequest({ + apiName: "Petstore", + organization: "acme", + cliVersion: "0.0.0", + generatorInvocation, + sdkVersion: "1.2.3", + specsTarGzBuffer: Buffer.from("archive") + }); + + const original = createRequest(invocation()); + const configured = createRequest(invocation({ config: { packageJson: { name: "@acme/sdk" } } })); + const github = createRequest( + invocation({ + outputMode: FernFiddle.OutputMode.githubV2( + FernFiddle.GithubOutputModeV2.push({ owner: "acme", repo: "sdk", branch: "main" }) + ) + }) + ); + + expect(configured.idempotencyKey).not.toBe(original.idempotencyKey); + expect(github.idempotencyKey).not.toBe(original.idempotencyKey); + }); + + it("submits and polls a multi-language group once", async () => { + process.env.FERN_SDK_GEN_API_ORIGIN = "https://sdk-gen-api.test"; + const specsTarGzBuffer = Buffer.from("archive"); + const typescript = invocation(); + const python = invocation({ + name: "fernapi/fern-python-sdk", + language: "python", + version: "4.64.1" + }); + const request = createFernSdkGenApiBatchRequest({ + apiName: "Petstore", + organization: "acme", + cliVersion: "0.0.0", + specsTarGzBuffer, + targets: [ + { + generatorInvocation: typescript, + sdkVersion: "1.2.3", + targetIdSeed: "0" + }, + { generatorInvocation: python, sdkVersion: "1.2.3", targetIdSeed: "1" } + ] + }); + const post = vi.spyOn(axios, "post").mockResolvedValue({ data: { buildId: "build-1" } } as never); + const get = vi.spyOn(axios, "get").mockResolvedValue({ + data: { + buildId: "build-1", + status: "succeeded", + targets: request.targets.map((target) => ({ + targetId: target.targetId, + status: "succeeded", + logs: [], + result: { + artifactUrl: `https://example.test/${target.targetId}.zip` + } + })) + } + } as never); + const context = { + logger: { debug: vi.fn(), info: vi.fn() }, + failAndThrow: (message: string) => { + throw new Error(message); + } + } as never; + const common = { + apiName: "Petstore", + organization: "acme", + cliVersion: "0.0.0", + sdkVersion: "1.2.3", + token: { value: "token" } as never, + specsTarGzBuffer, + absolutePathToPreview: undefined, + context + }; + const batch = new FernSdkGenApiBatch(2); + + const results = await Promise.all([ + batch.run({ + ...common, + generatorInvocation: typescript, + targetIdSeed: "0" + }), + batch.run({ ...common, generatorInvocation: python, targetIdSeed: "1" }) + ]); + + expect(post).toHaveBeenCalledTimes(1); + expect(get).toHaveBeenCalledTimes(1); + expect(results.map((result) => result.actualVersion)).toEqual(["1.2.3", "1.2.3"]); + }); + + it("stops polling when the build fails before a target reaches a terminal state", async () => { + process.env.FERN_SDK_GEN_API_ORIGIN = "https://sdk-gen-api.test"; + const specsTarGzBuffer = Buffer.from("archive"); + const generatorInvocation = invocation(); + const request = createFernSdkGenApiRequest({ + apiName: "Petstore", + organization: "acme", + cliVersion: "0.0.0", + generatorInvocation, + sdkVersion: "1.2.3", + specsTarGzBuffer + }); + vi.spyOn(axios, "post").mockResolvedValue({ data: { buildId: "build-1" } } as never); + const get = vi.spyOn(axios, "get").mockResolvedValue({ + data: { + buildId: "build-1", + status: "failed", + targets: [{ targetId: request.targets[0]?.targetId, status: "queued", logs: [] }] + } + } as never); + const context = { + logger: { debug: vi.fn(), info: vi.fn() }, + failAndThrow: (message: string) => { + throw new Error(message); + } + } as never; + + await expect( + runFernSdkGenApiBuild({ + apiName: "Petstore", + organization: "acme", + cliVersion: "0.0.0", + generatorInvocation, + sdkVersion: "1.2.3", + token: { value: "token" } as never, + specsTarGzBuffer, + absolutePathToPreview: undefined, + context + }) + ).rejects.toThrow("build ended with status failed"); + expect(get).toHaveBeenCalledTimes(1); + }); +}); + +describe("sdk-gen-api environment configuration", () => { + it("is disabled by default", () => { + vi.stubEnv("FERN_USE_SDK_GEN_API", undefined); + vi.stubEnv("DEFAULT_USE_SDK_GEN_API", undefined); + + expect(isFernSdkGenApiEnabled()).toBe(false); + }); + + it("uses the baked default when no runtime override is present", () => { + vi.stubEnv("FERN_USE_SDK_GEN_API", undefined); + vi.stubEnv("DEFAULT_USE_SDK_GEN_API", " true "); + + expect(isFernSdkGenApiEnabled()).toBe(true); + }); + + it("lets the runtime flag override the baked default", () => { + vi.stubEnv("FERN_USE_SDK_GEN_API", "false"); + vi.stubEnv("DEFAULT_USE_SDK_GEN_API", "true"); + + expect(isFernSdkGenApiEnabled()).toBe(false); + }); + + it("prefers the runtime origin and removes its trailing slash", () => { + vi.stubEnv("FERN_SDK_GEN_API_ORIGIN", "https://override.example.test/"); + vi.stubEnv("DEFAULT_SDK_GEN_API_ORIGIN", "https://default.example.test"); + + expect(getFernSdkGenApiOrigin()).toBe("https://override.example.test"); + }); + + it("uses the baked origin when no runtime override is present", () => { + vi.stubEnv("FERN_SDK_GEN_API_ORIGIN", undefined); + vi.stubEnv("DEFAULT_SDK_GEN_API_ORIGIN", "https://default.example.test/"); + + expect(getFernSdkGenApiOrigin()).toBe("https://default.example.test"); + }); + + it("allows HTTP only for loopback development origins", () => { + vi.stubEnv("FERN_SDK_GEN_API_ORIGIN", "http://localhost:3001/"); + expect(getFernSdkGenApiOrigin()).toBe("http://localhost:3001"); + + vi.stubEnv("FERN_SDK_GEN_API_ORIGIN", "http://127.0.0.1:3001/"); + expect(getFernSdkGenApiOrigin()).toBe("http://127.0.0.1:3001"); + }); + + it("rejects insecure remote origins", () => { + vi.stubEnv("FERN_SDK_GEN_API_ORIGIN", "http://sdk-gen-api.example.test"); + + expect(() => getFernSdkGenApiOrigin()).toThrow("must use HTTPS unless it targets localhost"); + }); +}); diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/fernSdkGenApi.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/fernSdkGenApi.ts new file mode 100644 index 000000000000..87fc990fd8d1 --- /dev/null +++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/fernSdkGenApi.ts @@ -0,0 +1,895 @@ +import { stripCliConfigKeys } from "@fern-api/api-workspace-commons"; +import { FernToken } from "@fern-api/auth"; +import { generatorsYml } from "@fern-api/configuration"; +import { AbsoluteFilePath, join, RelativeFilePath } from "@fern-api/fs-utils"; +import { isAutoVersion } from "@fern-api/generator-cli/autoversion"; +import { CliError, InteractiveTaskContext } from "@fern-api/task-context"; +import { FernFiddle } from "@fern-fern/fiddle-sdk"; +import axios, { AxiosError } from "axios"; +import { createHash } from "crypto"; +import FormData from "form-data"; +import path from "path"; +import { downloadFilesForTask } from "./RemoteTaskHandler.js"; + +const POLL_INTERVAL_MS = 2_000; +const POLL_TIMEOUT_MS = 15 * 60 * 1_000; +const REQUEST_TIMEOUT_MS = 60_000; +const LOOPBACK_HOSTNAMES = new Set(["localhost", "127.0.0.1", "[::1]", "::1"]); + +export type FernSdkGenApiLanguage = + | "typescript" + | "python" + | "java" + | "kotlin" + | "go" + | "csharp" + | "php" + | "ruby" + | "rust" + | "swift" + | "cli"; + +export type FernSdkGenApiPublishRegistry = + | "npm" + | "pypi" + | "maven" + | "nuget" + | "rubygems" + | "crates" + | "go" + | "composer"; + +export interface FernSdkGenApiPublishConfig { + registry: FernSdkGenApiPublishRegistry; + url?: string; +} + +export interface FernSdkGenApiPackageConfig { + packageName?: string; + moduleName?: string; + modulePath?: string; + namespace?: string; + groupId?: string; + artifactId?: string; +} + +export type FernSdkGenApiRequestedOutput = + | { type: "download" } + | { + type: "github"; + repository: string; + host?: string; + branch?: string; + mode?: "release" | "pull-request" | "push"; + reviewers?: { teams?: string[]; users?: string[] }; + publish?: FernSdkGenApiPublishConfig; + } + | { type: "publish"; publish: FernSdkGenApiPublishConfig }; + +/** + * First-party Fern SDK generators that can be represented by the shared SDK Config IR target + * languages. Keep aliases here because existing generators.yml files remain valid during the + * backend migration. + */ +const FERN_SDK_GENERATOR_LANGUAGES: Readonly> = { + "fernapi/fern-typescript": "typescript", + "fernapi/fern-typescript-sdk": "typescript", + "fernapi/fern-typescript-node-sdk": "typescript", + "fernapi/fern-typescript-browser-sdk": "typescript", + "fernapi/fern-python-sdk": "python", + "fernapi/fern-java-sdk": "java", + "fernapi/fern-kotlin-sdk": "kotlin", + "fernapi/fern-go-sdk": "go", + "fernapi/fern-csharp-sdk": "csharp", + "fernapi/fern-php-sdk": "php", + "fernapi/fern-ruby-sdk": "ruby", + "fernapi/fern-ruby-sdk-v2": "ruby", + "fernapi/fern-rust-sdk": "rust", + "fernapi/fern-swift-sdk": "swift", + "fernapi/fern-cli": "cli", + "fernapi/fern-cli-generator": "cli" +}; + +interface FernBuildStatus { + buildId: string; + status: "queued" | "running" | "succeeded" | "failed" | "partial_failure"; + targets: Array<{ + targetId: string; + status: "queued" | "running" | "succeeded" | "failed"; + logs: Array<{ level: string; message: string }>; + result?: { artifactUrl: string; actualVersion?: string }; + error?: { message: string }; + }>; +} + +export interface FernSdkGenApiRequest { + protocolVersion: 1; + apiName: string; + cliVersion?: string; + idempotencyKey: string; + apiInputs: Array<{ id: string; specIndexes: "all" }>; + targets: Array<{ + targetId: string; + apiInputId: string; + language: FernSdkGenApiLanguage; + sdk: { name: string; version: string }; + fernGenerator: { id: string; version: string }; + package?: FernSdkGenApiPackageConfig; + invocation: { + customConfig: Record; + keywords: string[]; + smartCasing: boolean; + smartCasingDigitWordBoundary: boolean; + disableExamples: boolean; + audiences?: string[]; + readme?: Record; + settings?: Record; + apiOverride?: Record; + }; + requestedOutput: FernSdkGenApiRequestedOutput; + }>; +} + +export function isFernSdkGenApiEnabled(): boolean { + const configured = process.env.FERN_USE_SDK_GEN_API ?? process.env.DEFAULT_USE_SDK_GEN_API ?? "false"; + return configured.trim().toLowerCase() === "true"; +} + +export function getFernSdkGenApiOrigin(): string | undefined { + const configured = process.env.FERN_SDK_GEN_API_ORIGIN ?? process.env.DEFAULT_SDK_GEN_API_ORIGIN; + if (configured == null) { + return undefined; + } + + let origin: URL; + try { + origin = new URL(configured); + } catch { + throw new Error("FERN_SDK_GEN_API_ORIGIN must be a valid URL"); + } + if (origin.username.length > 0 || origin.password.length > 0) { + throw new Error("FERN_SDK_GEN_API_ORIGIN must not contain credentials"); + } + const isLoopbackHttp = origin.protocol === "http:" && LOOPBACK_HOSTNAMES.has(origin.hostname); + if (origin.protocol !== "https:" && !isLoopbackHttp) { + throw new Error("FERN_SDK_GEN_API_ORIGIN must use HTTPS unless it targets localhost"); + } + return origin.toString().replace(/\/$/, ""); +} + +export function getFernSdkGenApiLanguage(generatorName: string): FernSdkGenApiLanguage | undefined { + return FERN_SDK_GENERATOR_LANGUAGES[generatorName]; +} + +interface FernSdkGenApiOutputMapping { + package?: FernSdkGenApiPackageConfig; + requestedOutput: FernSdkGenApiRequestedOutput; +} + +/** + * Preserves Fern's delivery and publication intent without forwarding credentials. The shared + * config contract carries externally managed credential references; resolving Fern secrets into + * those references belongs to the downstream distribution workstream. + */ +export function mapFernSdkGenApiOutput( + generatorInvocation: generatorsYml.GeneratorInvocation +): FernSdkGenApiOutputMapping { + const outputMode = generatorInvocation.outputMode; + switch (outputMode.type) { + case "downloadFiles": + return { requestedOutput: { type: "download" } }; + case "github": + return mapGithubOutput({ + owner: outputMode.owner, + repo: outputMode.repo, + branch: outputMode.branch, + mode: outputMode.makePr === true ? "pull-request" : "release", + publishInfo: outputMode.publishInfo + }); + case "githubV2": { + const github = outputMode.githubV2; + return mapGithubOutput({ + owner: github.owner, + repo: github.repo, + host: github.host, + branch: github.branch, + mode: github.type === "pullRequest" ? "pull-request" : github.type === "push" ? "push" : "release", + reviewers: github.type === "pullRequest" ? mapGithubReviewers(github.reviewers) : undefined, + publishInfo: github.publishInfo + }); + } + case "publishV2": { + const mapped = mapPublishOutputV2(outputMode.publishV2); + return { + ...(mapped.package != null ? { package: mapped.package } : {}), + requestedOutput: { type: "publish", publish: mapped.publish } + }; + } + case "publish": { + const mapped = mapLegacyPublishOutput(generatorInvocation, outputMode.registryOverrides); + return { + ...(mapped.package != null ? { package: mapped.package } : {}), + requestedOutput: { type: "publish", publish: mapped.publish } + }; + } + } +} + +function mapGithubOutput({ + owner, + repo, + host, + branch, + mode, + reviewers, + publishInfo +}: { + owner: string; + repo: string; + host?: string; + branch?: string; + mode: "release" | "pull-request" | "push"; + reviewers?: { teams?: string[]; users?: string[] }; + publishInfo?: FernFiddle.GithubPublishInfo; +}): FernSdkGenApiOutputMapping { + const publication = publishInfo != null ? mapGithubPublishInfo(publishInfo) : undefined; + // TODO: Before broadly enabling this route, require downstream credential resolution to bind + // credentials to approved GitHub installations/repositories and registry hosts/package namespaces. + return { + ...(publication?.package != null ? { package: publication.package } : {}), + requestedOutput: { + type: "github", + repository: `${owner}/${repo}`, + ...(host != null ? { host } : {}), + ...(branch != null ? { branch } : {}), + mode, + ...(reviewers != null ? { reviewers } : {}), + ...(publication != null ? { publish: publication.publish } : {}) + } + }; +} + +function mapGithubReviewers( + reviewers: FernFiddle.GithubPullRequestReviewer[] | undefined +): { teams?: string[]; users?: string[] } | undefined { + if (reviewers == null) { + return undefined; + } + const teams = reviewers.filter((reviewer) => reviewer.type === "team").map((reviewer) => reviewer.name); + const users = reviewers.filter((reviewer) => reviewer.type === "user").map((reviewer) => reviewer.name); + if (teams.length === 0 && users.length === 0) { + return undefined; + } + return { + ...(teams.length > 0 ? { teams } : {}), + ...(users.length > 0 ? { users } : {}) + }; +} + +interface FernSdkGenApiPublicationMapping { + package?: FernSdkGenApiPackageConfig; + publish: FernSdkGenApiPublishConfig; +} + +function mapPublishOutputV2(publish: FernFiddle.PublishOutputModeV2): FernSdkGenApiPublicationMapping { + switch (publish.type) { + case "npmOverride": + return mapNpmPublish(publish.npmOverride); + case "mavenOverride": + return mapMavenPublish(publish.mavenOverride); + case "pypiOverride": + return mapPypiPublish(publish.pypiOverride); + case "rubyGemsOverride": + return mapNamedPublish("rubygems", publish.rubyGemsOverride); + case "nugetOverride": + return mapNamedPublish("nuget", publish.nugetOverride); + case "cratesOverride": + return mapNamedPublish("crates", publish.cratesOverride); + case "postman": + throw new Error("sdk-gen-api does not support Postman collection publication as an SDK output"); + } +} + +function mapGithubPublishInfo(publish: FernFiddle.GithubPublishInfo): FernSdkGenApiPublicationMapping { + switch (publish.type) { + case "npm": + return mapNpmPublish(publish); + case "maven": + return mapMavenPublish(publish); + case "pypi": + return mapPypiPublish(publish); + case "rubygems": + return mapNamedPublish("rubygems", publish); + case "nuget": + return mapNamedPublish("nuget", publish); + case "crates": + return mapNamedPublish("crates", publish); + case "postman": + throw new Error("sdk-gen-api does not support Postman collection publication as an SDK output"); + } +} + +function mapNpmPublish( + output: Pick | undefined +): FernSdkGenApiPublicationMapping { + return { + ...(output?.packageName ? { package: { packageName: output.packageName } } : {}), + publish: { + registry: "npm", + ...(output?.registryUrl ? { url: output.registryUrl } : {}) + } + }; +} + +function mapPypiPublish( + output: + | Pick + | Pick + | undefined +): FernSdkGenApiPublicationMapping { + const packageName = output != null && "coordinate" in output ? output.coordinate : output?.packageName; + return { + ...(packageName ? { package: { packageName } } : {}), + publish: { + registry: "pypi", + ...(output?.registryUrl ? { url: output.registryUrl } : {}) + } + }; +} + +function mapMavenPublish( + output: Pick | undefined +): FernSdkGenApiPublicationMapping { + const packageConfig = output?.coordinate != null ? packageFromMavenCoordinate(output.coordinate) : undefined; + return { + ...(packageConfig != null ? { package: packageConfig } : {}), + publish: { + registry: "maven", + ...(output?.registryUrl ? { url: output.registryUrl } : {}) + } + }; +} + +function mapNamedPublish( + registry: "nuget" | "rubygems" | "crates", + output: { registryUrl: string; packageName: string } | undefined +): FernSdkGenApiPublicationMapping { + return { + ...(output?.packageName ? { package: { packageName: output.packageName } } : {}), + publish: { + registry, + ...(output?.registryUrl ? { url: output.registryUrl } : {}) + } + }; +} + +function packageFromMavenCoordinate(coordinate: string): FernSdkGenApiPackageConfig { + const [groupId, artifactId] = coordinate.split(":"); + if (!groupId || !artifactId) { + throw new Error(`Invalid Maven coordinate for sdk-gen-api: ${coordinate}`); + } + return { groupId, artifactId }; +} + +function mapLegacyPublishOutput( + generatorInvocation: generatorsYml.GeneratorInvocation, + overrides: FernFiddle.RegistryOverrides +): FernSdkGenApiPublicationMapping { + const language = getFernSdkGenApiLanguage(generatorInvocation.name); + if (language === "typescript" && overrides.npm != null) { + return mapNpmPublish(overrides.npm); + } + if ((language === "java" || language === "kotlin") && overrides.maven != null) { + return mapMavenPublish(overrides.maven); + } + const registry = defaultPublishRegistry(language); + if (registry == null) { + throw new Error(`sdk-gen-api cannot infer a registry for ${language ?? generatorInvocation.name}`); + } + return { publish: { registry } }; +} + +function defaultPublishRegistry(language: FernSdkGenApiLanguage | undefined): FernSdkGenApiPublishRegistry | undefined { + switch (language) { + case "typescript": + return "npm"; + case "python": + return "pypi"; + case "java": + case "kotlin": + return "maven"; + case "go": + return "go"; + case "csharp": + return "nuget"; + case "php": + return "composer"; + case "ruby": + return "rubygems"; + case "rust": + return "crates"; + case "swift": + case "cli": + case undefined: + return undefined; + } +} + +export interface FernSdkGenApiCandidate { + generatorInvocation: generatorsYml.GeneratorInvocation; + sdkVersion: string | undefined; + specsTarGzBuffer: Buffer | undefined; + whitelabel?: FernFiddle.WhitelabelConfig; +} + +export interface EligibleFernSdkGenApiCandidate extends FernSdkGenApiCandidate { + sdkVersion: string; + specsTarGzBuffer: Buffer; +} + +export function isEligibleForFernSdkGenApi( + candidate: FernSdkGenApiCandidate +): candidate is EligibleFernSdkGenApiCandidate { + const { generatorInvocation, sdkVersion, specsTarGzBuffer, whitelabel } = candidate; + const language = getFernSdkGenApiLanguage(generatorInvocation.name); + // Fiddle currently replaces AUTO after generation. Until that step moves into the shared + // pipeline, forwarding AUTO would write the literal placeholder into generated packages. + const hasConcreteVersion = sdkVersion != null && sdkVersion.trim().length > 0 && !isAutoVersion(sdkVersion); + return ( + language != null && + (generatorInvocation.language == null || generatorInvocation.language === language) && + hasConcreteVersion && + specsTarGzBuffer != null && + whitelabel == null + ); +} + +export interface FernSdkGenApiBuildParameters { + apiName: string; + organization: string; + cliVersion: string | undefined; + generatorInvocation: generatorsYml.GeneratorInvocation; + sdkVersion: string; + token: FernToken; + specsTarGzBuffer: Buffer; + absolutePathToPreview: AbsoluteFilePath | undefined; + context: InteractiveTaskContext; + targetIdSeed?: string; + audiences?: string[]; + skipFernignore?: boolean; +} + +export interface FernSdkGenApiBuildResponse { + createdSnippets: false; + snippetsS3PreSignedReadUrl: undefined; + actualVersion: string; + pullRequestUrl: undefined; + noChangesDetected: undefined; + publishTarget: undefined; +} + +interface FernSdkGenApiBatchParticipant extends FernSdkGenApiBuildParameters { + resolve: (response: FernSdkGenApiBuildResponse) => void; + reject: (error: unknown) => void; +} + +/** + * Coordinates the generators in one Fern group so they remain one multi-target backend build. + * Each generator keeps its own task context and output directory, while submission and polling + * happen once for the group. + */ +export class FernSdkGenApiBatch { + private expectedTargets: number; + private readonly participants: FernSdkGenApiBatchParticipant[] = []; + private terminalError: unknown; + private dispatched = false; + + public constructor(expectedTargets: number) { + if (expectedTargets < 1) { + throw new Error("A Fern sdk-gen-api batch must expect at least one target"); + } + this.expectedTargets = expectedTargets; + } + + public run(parameters: FernSdkGenApiBuildParameters): Promise { + if (this.terminalError != null) { + return Promise.reject(this.terminalError); + } + if (this.dispatched) { + return Promise.reject(new Error("The Fern sdk-gen-api batch was already dispatched")); + } + return new Promise((resolve, reject) => { + this.participants.push({ ...parameters, resolve, reject }); + this.dispatchIfReady(); + }); + } + + /** Removes a statically selected target that became ineligible after SDK-version/source resolution. */ + public skip(): void { + if (this.dispatched || this.terminalError != null) { + return; + } + this.expectedTargets -= 1; + this.dispatchIfReady(); + } + + /** Prevents siblings waiting at the batch barrier from hanging if preparation of one fails. */ + public cancel(error: unknown): void { + if (this.dispatched || this.terminalError != null) { + return; + } + this.terminalError = error; + for (const participant of this.participants) { + participant.reject(error); + } + } + + private dispatchIfReady(): void { + if (this.dispatched || this.terminalError != null || this.participants.length !== this.expectedTargets) { + return; + } + this.dispatched = true; + void this.dispatch(); + } + + private async dispatch(): Promise { + try { + const results = await executeFernSdkGenApiBuild(this.participants); + results.forEach((result, index) => { + const participant = this.participants[index]; + if (result.status === "fulfilled") { + participant?.resolve(result.value); + } else { + participant?.reject(result.reason); + } + }); + } catch (error) { + this.terminalError = error; + for (const participant of this.participants) { + participant.reject(error); + } + } + } +} + +export async function runFernSdkGenApiBuild( + parameters: FernSdkGenApiBuildParameters +): Promise { + const [result] = await executeFernSdkGenApiBuild([parameters]); + if (result?.status === "fulfilled") { + return result.value; + } + throw result?.reason ?? new Error("sdk-gen-api did not return the requested target"); +} + +async function executeFernSdkGenApiBuild( + participants: FernSdkGenApiBuildParameters[] +): Promise[]> { + const first = participants[0]; + if (first == null) { + throw new Error("Cannot submit an empty Fern sdk-gen-api build"); + } + let origin: string | undefined; + try { + origin = getFernSdkGenApiOrigin(); + } catch (error) { + return first.context.failAndThrow( + error instanceof Error ? error.message : "Invalid sdk-gen-api origin", + error, + { + code: CliError.Code.ConfigError + } + ); + } + if (!origin) { + return first.context.failAndThrow( + "FERN_SDK_GEN_API_ORIGIN is required when FERN_USE_SDK_GEN_API=true", + undefined, + { code: CliError.Code.ConfigError } + ); + } + + assertSameBatchInput(participants); + const request = createFernSdkGenApiBatchRequest({ + apiName: first.apiName, + organization: first.organization, + cliVersion: first.cliVersion, + specsTarGzBuffer: first.specsTarGzBuffer, + targets: participants.map((participant) => ({ + generatorInvocation: participant.generatorInvocation, + sdkVersion: participant.sdkVersion, + targetIdSeed: participant.targetIdSeed, + audiences: participant.audiences + })) + }); + + const form = new FormData(); + form.append("request", JSON.stringify(request)); + form.append("sources", first.specsTarGzBuffer, { + filename: "specs.tar.gz", + contentType: "application/gzip" + }); + + let buildId: string; + try { + const response = await axios.post<{ buildId: string }>(`${origin}/v1/fern/build`, form, { + headers: { + ...form.getHeaders(), + // TODO: Replace the reusable Fern bearer token with a short-lived, audience-restricted + // sdk-generation token once cross-service token exchange is available. + Authorization: `Bearer ${first.token.value}`, + "X-Fern-Organization-Id": first.organization + }, + maxBodyLength: 30 * 1024 * 1024, + timeout: REQUEST_TIMEOUT_MS + }); + buildId = response.data.buildId; + } catch (error) { + const axiosError = error as AxiosError<{ message?: string }>; + return first.context.failAndThrow( + `Failed to submit sdk-gen-api build: ${axiosError.response?.data?.message ?? axiosError.message}`, + error, + { code: CliError.Code.NetworkError } + ); + } + + for (const participant of participants) { + participant.context.logger.debug(`sdk-gen-api build ID: ${buildId}`); + } + const loggedByTarget = new Map(); + const pollDeadline = Date.now() + POLL_TIMEOUT_MS; + for (;;) { + let status: FernBuildStatus; + try { + const response = await axios.get(`${origin}/v1/fern/build/${buildId}`, { + headers: { + Authorization: `Bearer ${first.token.value}`, + "X-Fern-Organization-Id": first.organization + }, + timeout: REQUEST_TIMEOUT_MS + }); + status = response.data; + } catch (error) { + return first.context.failAndThrow("Failed to poll sdk-gen-api build", error, { + code: CliError.Code.NetworkError + }); + } + + const missingTarget = request.targets.find( + (requestTarget) => !status.targets.some((target) => target.targetId === requestTarget.targetId) + ); + if (missingTarget != null) { + return first.context.failAndThrow( + `sdk-gen-api response did not contain target ${missingTarget.targetId}`, + undefined, + { code: CliError.Code.InternalError } + ); + } + + for (const [index, requestTarget] of request.targets.entries()) { + const target = status.targets.find((candidate) => candidate.targetId === requestTarget.targetId); + const context = participants[index]?.context; + if (target == null || context == null) { + continue; + } + const logged = loggedByTarget.get(target.targetId) ?? 0; + for (const log of target.logs.slice(logged)) { + context.logger.info(log.message); + } + loggedByTarget.set(target.targetId, target.logs.length); + } + + const allTargetsTerminal = request.targets.every((requestTarget) => isTerminal(status, requestTarget.targetId)); + if (allTargetsTerminal || status.status === "failed" || status.status === "succeeded") { + return Promise.allSettled( + participants.map((participant, index) => + finishFernSdkGenApiTarget(participant, request.targets[index]?.targetId, status) + ) + ); + } + if (Date.now() >= pollDeadline) { + return first.context.failAndThrow( + `Timed out waiting for sdk-gen-api build ${buildId} after ${POLL_TIMEOUT_MS / 60_000} minutes`, + undefined, + { code: CliError.Code.NetworkError } + ); + } + await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS)); + } +} + +function isTerminal(status: FernBuildStatus, targetId: string): boolean { + const target = status.targets.find((candidate) => candidate.targetId === targetId); + return target?.status === "failed" || target?.status === "succeeded"; +} + +async function finishFernSdkGenApiTarget( + participant: FernSdkGenApiBuildParameters, + targetId: string | undefined, + status: FernBuildStatus +): Promise { + const target = status.targets.find((candidate) => candidate.targetId === targetId); + if (target == null) { + return participant.context.failAndThrow( + "sdk-gen-api response did not contain the requested target", + undefined, + { + code: CliError.Code.InternalError + } + ); + } + if (target.status === "failed") { + return participant.context.failAndThrow(target.error?.message ?? "sdk-gen-api generation failed", undefined, { + code: CliError.Code.ContainerError + }); + } + if (target.status !== "succeeded") { + return participant.context.failAndThrow( + `sdk-gen-api build ended with status ${status.status} while target ${target.targetId} remained ${target.status}`, + undefined, + { code: CliError.Code.InternalError } + ); + } + if (target.result?.artifactUrl == null) { + return participant.context.failAndThrow("sdk-gen-api target completed without an artifact URL", undefined, { + code: CliError.Code.InternalError + }); + } + const outputPath = + participant.absolutePathToPreview != null + ? join( + participant.absolutePathToPreview, + RelativeFilePath.of(path.basename(participant.generatorInvocation.name)) + ) + : participant.generatorInvocation.absolutePathToLocalOutput; + if (outputPath != null) { + await downloadFilesForTask({ + s3PreSignedReadUrl: target.result.artifactUrl, + absolutePathToLocalOutput: outputPath, + context: participant.context, + skipFernignore: participant.skipFernignore + }); + } + return { + createdSnippets: false, + snippetsS3PreSignedReadUrl: undefined, + actualVersion: target.result.actualVersion ?? participant.sdkVersion, + pullRequestUrl: undefined, + noChangesDetected: undefined, + publishTarget: undefined + }; +} + +function assertSameBatchInput(participants: FernSdkGenApiBuildParameters[]): void { + const first = participants[0]; + if (first == null) { + return; + } + const sourceHash = createHash("sha256").update(first.specsTarGzBuffer).digest("hex"); + for (const participant of participants.slice(1)) { + const participantSourceHash = createHash("sha256").update(participant.specsTarGzBuffer).digest("hex"); + if ( + participant.apiName !== first.apiName || + participant.organization !== first.organization || + participant.token.value !== first.token.value || + participantSourceHash !== sourceHash + ) { + throw new Error("Fern sdk-gen-api batch targets must share API, organization, token, and sources"); + } + } +} + +export function createFernSdkGenApiRequest({ + apiName, + organization, + cliVersion, + generatorInvocation, + sdkVersion, + specsTarGzBuffer +}: { + apiName: string; + organization: string; + cliVersion: string | undefined; + generatorInvocation: generatorsYml.GeneratorInvocation; + sdkVersion: string; + specsTarGzBuffer: Buffer; +}): FernSdkGenApiRequest { + return createFernSdkGenApiBatchRequest({ + apiName, + organization, + cliVersion, + specsTarGzBuffer, + targets: [{ generatorInvocation, sdkVersion }] + }); +} + +export function createFernSdkGenApiBatchRequest({ + apiName, + organization, + cliVersion, + specsTarGzBuffer, + targets +}: { + apiName: string; + organization: string; + cliVersion: string | undefined; + specsTarGzBuffer: Buffer; + targets: Array<{ + generatorInvocation: generatorsYml.GeneratorInvocation; + sdkVersion: string; + targetIdSeed?: string; + audiences?: string[]; + }>; +}): FernSdkGenApiRequest { + if (targets.length === 0) { + throw new Error("Cannot create an empty Fern sdk-gen-api request"); + } + const requestTargets = targets.map(({ generatorInvocation, sdkVersion, targetIdSeed, audiences }, index) => { + const language = getFernSdkGenApiLanguage(generatorInvocation.name); + if (language == null) { + throw new Error(`Unsupported Fern SDK generator: ${generatorInvocation.name}`); + } + const output = mapFernSdkGenApiOutput(generatorInvocation); + const targetId = createHash("sha256") + .update( + `${apiName}:${generatorInvocation.name}:${generatorInvocation.version}:${targetIdSeed ?? index.toString()}` + ) + .digest("hex") + .slice(0, 20); + return { + targetId, + apiInputId: "default", + language, + sdk: { name: apiName, version: sdkVersion }, + fernGenerator: { + id: generatorInvocation.name, + version: generatorInvocation.version + }, + ...(output.package != null ? { package: output.package } : {}), + invocation: { + customConfig: (stripCliConfigKeys(generatorInvocation.config) ?? {}) as Record, + keywords: generatorInvocation.keywords ?? [], + smartCasing: generatorInvocation.smartCasing, + smartCasingDigitWordBoundary: generatorInvocation.smartCasingDigitWordBoundary, + disableExamples: generatorInvocation.disableExamples, + ...(audiences != null ? { audiences } : {}), + ...(generatorInvocation.readme != null + ? { readme: generatorInvocation.readme as Record } + : {}), + ...(generatorInvocation.settings != null + ? { + settings: generatorInvocation.settings as Record + } + : {}), + ...(generatorInvocation.apiOverride != null + ? { + apiOverride: generatorInvocation.apiOverride as Record + } + : {}) + }, + requestedOutput: output.requestedOutput + }; + }); + const apiInputs: FernSdkGenApiRequest["apiInputs"] = [{ id: "default", specIndexes: "all" }]; + const idempotencyKey = createHash("sha256") + .update(specsTarGzBuffer) + .update( + JSON.stringify({ + protocolVersion: 1, + organization, + apiName, + apiInputs, + targets: requestTargets + }) + ) + .digest("hex"); + + return { + protocolVersion: 1, + apiName, + ...(cliVersion ? { cliVersion } : {}), + idempotencyKey, + apiInputs, + targets: requestTargets + }; +} diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/index.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/index.ts index 9a28538e5208..f75914b7c7ab 100644 --- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/index.ts +++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/index.ts @@ -1,4 +1,5 @@ export { findGeneratorLineNumber, GeneratorOccurrenceTracker, getOutputRepoUrl } from "./automationMetadata.js"; +export { getFernSdkGenApiLanguage, isFernSdkGenApiEnabled } from "./fernSdkGenApi.js"; export { getDynamicGeneratorConfig } from "./getDynamicGeneratorConfig.js"; export type { PublishTarget } from "./publishTarget.js"; export { extractPublishTarget } from "./publishTarget.js"; diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForAPIWorkspace.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForAPIWorkspace.ts index e7f352143070..9faa710f9af5 100644 --- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForAPIWorkspace.ts +++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForAPIWorkspace.ts @@ -15,6 +15,7 @@ import { appendFile } from "fs/promises"; import { findGeneratorLineNumber, GeneratorOccurrenceTracker, getOutputRepoUrl } from "./automationMetadata.js"; import { downloadSnippetsForTask } from "./downloadSnippetsForTask.js"; +import { FernSdkGenApiBatch, getFernSdkGenApiLanguage, isFernSdkGenApiEnabled } from "./fernSdkGenApi.js"; import type { PublishTarget } from "./publishTarget.js"; import type { AutomationRunOptions } from "./RemoteGeneratorRunRecorder.js"; import { resolveAutoDiscoveredFernignorePath } from "./resolveAutoDiscoveredFernignorePath.js"; @@ -143,9 +144,18 @@ export async function runRemoteGenerationForAPIWorkspace({ effectiveOccurrenceTracker.recordOccurrences(generatorGroup.generators); } const generatorsYmlAbsolutePath = workspace.generatorsConfiguration?.absolutePathToConfiguration; + const sdkGenApiCandidateIndexes = new Set( + isFernSdkGenApiEnabled() + ? generatorGroup.generators.flatMap((generator, index) => + getFernSdkGenApiLanguage(generator.name) != null ? [index] : [] + ) + : [] + ); + const sdkGenApiBatch = + sdkGenApiCandidateIndexes.size > 1 ? new FernSdkGenApiBatch(sdkGenApiCandidateIndexes.size) : undefined; const results = await Promise.all( - generatorGroup.generators.map((generatorInvocation) => + generatorGroup.generators.map((generatorInvocation, generatorIndex) => context.runInteractiveTask({ name: generatorInvocation.name }, (interactiveTaskContext) => generateOne({ generatorInvocation, @@ -183,6 +193,8 @@ export async function runRemoteGenerationForAPIWorkspace({ occurrenceTracker: effectiveOccurrenceTracker, loginCommand, getSpecsTarGzBuffer, + sdkGenApiBatch: sdkGenApiCandidateIndexes.has(generatorIndex) ? sdkGenApiBatch : undefined, + sdkGenApiTargetIdSeed: generatorIndex.toString(), generateFullProject, onSnippetsProduced: (invocation) => snippetsProducedBy.push(invocation) }) @@ -242,6 +254,8 @@ async function generateOne({ occurrenceTracker, loginCommand, getSpecsTarGzBuffer, + sdkGenApiBatch, + sdkGenApiTargetIdSeed, generateFullProject, onSnippetsProduced }: { @@ -279,6 +293,8 @@ async function generateOne({ occurrenceTracker: GeneratorOccurrenceTracker; loginCommand: string | undefined; getSpecsTarGzBuffer: ((generatorName: string) => Promise) | undefined; + sdkGenApiBatch: FernSdkGenApiBatch | undefined; + sdkGenApiTargetIdSeed: string; generateFullProject: boolean | undefined; /** Invoked post-success when the generator produced snippets. */ onSnippetsProduced: (invocation: generatorsYml.GeneratorInvocation) => void; @@ -365,6 +381,8 @@ async function generateOne({ disableTelemetry, loginCommand, specsTarGzBuffer: await getSpecsTarGzBuffer?.(generatorInvocation.name), + sdkGenApiBatch, + sdkGenApiTargetIdSeed, generateFullProject }); @@ -418,6 +436,7 @@ async function generateOne({ isAutomation: automation != null }); } catch (error) { + sdkGenApiBatch?.cancel(error); if (automation == null) { throw error; } diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForGenerator.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForGenerator.ts index 5bc7483997af..2e3ca4497e8c 100644 --- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForGenerator.ts +++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForGenerator.ts @@ -32,6 +32,13 @@ import { CliError, InteractiveTaskContext } from "@fern-api/task-context"; import { FernWorkspace, IdentifiableSource } from "@fern-api/workspace-loader"; import { FernFiddle } from "@fern-fern/fiddle-sdk"; import { createAndStartJob } from "./createAndStartJob.js"; +import { + FernSdkGenApiBatch, + getFernSdkGenApiLanguage, + isEligibleForFernSdkGenApi, + isFernSdkGenApiEnabled, + runFernSdkGenApiBuild +} from "./fernSdkGenApi.js"; import { getDynamicGeneratorConfig } from "./getDynamicGeneratorConfig.js"; import { pollJobAndReportStatus } from "./pollJobAndReportStatus.js"; import { RemoteTaskHandler } from "./RemoteTaskHandler.js"; @@ -68,6 +75,8 @@ export async function runRemoteGenerationForGenerator({ disableTelemetry, loginCommand, specsTarGzBuffer, + sdkGenApiBatch, + sdkGenApiTargetIdSeed, generateFullProject }: { projectConfig: fernConfigJson.ProjectConfig; @@ -118,6 +127,8 @@ export async function runRemoteGenerationForGenerator({ */ loginCommand?: string; specsTarGzBuffer?: Buffer; + sdkGenApiBatch?: FernSdkGenApiBatch; + sdkGenApiTargetIdSeed?: string; /** * When true, filesystem (local-file-system / download) outputs are generated as full, * packageable projects (pyproject.toml, README.md, etc.) instead of source-only output. @@ -354,81 +365,148 @@ export async function runRemoteGenerationForGenerator({ }; } - const job = await createAndStartJob({ - projectConfig, - workspace, - organization, - generatorInvocation: generatorInvocationWithEnvVarSubstitutions, - context: interactiveTaskContext, - version: resolvedVersion, - intermediateRepresentation: { - ...ir, - fdrApiDefinitionId, - publishConfig: getPublishConfig({ - generatorInvocation: generatorInvocationWithEnvVarSubstitutions, - version: resolvedVersion, - userProvidedVersion: version, - packageName, - selfHosted: ir.selfHosted ?? false, - generateFullProject, - context: interactiveTaskContext - }) - }, - shouldLogS3Url, - token, - whitelabel: whitelabel != null ? substituteEnvVars(whitelabel) : undefined, - replay, - irVersionOverride, - absolutePathToPreview, - fiddlePreview, - pushPreviewBranch, - fernignorePath, - skipFernignore, - retryRateLimited, - automationMode, - autoMerge, - skipIfNoDiff, - verify, - loginCommand, - specsTarGzBuffer - }); - interactiveTaskContext.logger.debug(`Job ID: ${job.jobId}`); + let result: RemoteTaskHandler.Response | undefined; + let usedSdkGenApi = false; + const sdkGenApiEnabled = isFernSdkGenApiEnabled(); + const sdkGenApiLanguage = getFernSdkGenApiLanguage(generatorInvocationWithEnvVarSubstitutions.name); + if (sdkGenApiEnabled && sdkGenApiLanguage != null) { + if (replay?.enabled === true) { + return interactiveTaskContext.failAndThrow("sdk-gen-api does not yet support replay", undefined, { + code: CliError.Code.ConfigError + }); + } + if (generateFullProject === true) { + return interactiveTaskContext.failAndThrow( + "sdk-gen-api does not yet support full-project generation", + undefined, + { code: CliError.Code.ConfigError } + ); + } + const candidate = { + generatorInvocation: generatorInvocationWithEnvVarSubstitutions, + sdkVersion: resolvedVersion, + specsTarGzBuffer, + whitelabel + }; + if (!isEligibleForFernSdkGenApi(candidate)) { + const reason = + resolvedVersion == null + ? "the SDK version could not be resolved" + : isAutoVersion(resolvedVersion) + ? "automatic SDK versioning has not yet moved from Fiddle to the shared pipeline" + : whitelabel != null + ? "whitelabel generation has not yet moved from Fiddle to the shared pipeline" + : specsTarGzBuffer == null + ? "the source archive is unavailable" + : `generator language ${generatorInvocationWithEnvVarSubstitutions.language ?? "unknown"} does not match ${sdkGenApiLanguage}`; + return interactiveTaskContext.failAndThrow( + `Cannot submit SDK generation to sdk-gen-api: ${reason}`, + undefined, + { + code: CliError.Code.ConfigError + } + ); + } + if (verify === true) { + interactiveTaskContext.logger.warn("sdk-gen-api does not yet run Fern's post-generation verification step"); + } + const parameters = { + apiName: getOriginalName(ir.apiName), + organization, + cliVersion: workspace.cliVersion, + generatorInvocation: candidate.generatorInvocation, + sdkVersion: candidate.sdkVersion, + token, + specsTarGzBuffer: candidate.specsTarGzBuffer, + absolutePathToPreview, + context: interactiveTaskContext, + targetIdSeed: sdkGenApiTargetIdSeed, + audiences: audiences.type === "select" ? audiences.audiences : undefined, + skipFernignore + }; + result = await (sdkGenApiBatch?.run(parameters) ?? runFernSdkGenApiBuild(parameters)); + usedSdkGenApi = true; + } else { + sdkGenApiBatch?.skip(); + } - const taskId = job.taskIds[0]; - if (taskId == null) { - interactiveTaskContext.failAndThrow("Did not receive a task ID.", undefined, { - code: CliError.Code.NetworkError + if (!usedSdkGenApi) { + const job = await createAndStartJob({ + projectConfig, + workspace, + organization, + generatorInvocation: generatorInvocationWithEnvVarSubstitutions, + context: interactiveTaskContext, + version: resolvedVersion, + intermediateRepresentation: { + ...ir, + fdrApiDefinitionId, + publishConfig: getPublishConfig({ + generatorInvocation: generatorInvocationWithEnvVarSubstitutions, + version: resolvedVersion, + userProvidedVersion: version, + packageName, + selfHosted: ir.selfHosted ?? false, + generateFullProject, + context: interactiveTaskContext + }) + }, + shouldLogS3Url, + token, + whitelabel: whitelabel != null ? substituteEnvVars(whitelabel) : undefined, + replay, + irVersionOverride, + absolutePathToPreview, + fiddlePreview, + pushPreviewBranch, + fernignorePath, + skipFernignore, + retryRateLimited, + automationMode, + autoMerge, + skipIfNoDiff, + verify, + loginCommand, + specsTarGzBuffer }); - return undefined; - } - interactiveTaskContext.logger.debug(`Task ID: ${taskId}`); - - const taskHandler = new RemoteTaskHandler({ - job, - taskId, - generatorInvocation, - interactiveTaskContext, - absolutePathToPreview, - telemetryContext: { - cliVersion: workspace.cliVersion, - orgId: projectConfig.organization, - automationMode: automationMode === true, - autoMerge: autoMerge === true, - skipIfNoDiff: skipIfNoDiff === true, - versionArg: version == null ? "none" : isAutoVersion(version) ? "auto" : "explicit", - versionBump: undefined, - replayConfigEnabled: replay?.enabled === true, - noReplayFlag: noReplay === true, - disableTelemetry: disableTelemetry === true + interactiveTaskContext.logger.debug(`Job ID: ${job.jobId}`); + + const taskId = job.taskIds[0]; + if (taskId == null) { + interactiveTaskContext.failAndThrow("Did not receive a task ID.", undefined, { + code: CliError.Code.NetworkError + }); + return undefined; } - }); + interactiveTaskContext.logger.debug(`Task ID: ${taskId}`); + + const taskHandler = new RemoteTaskHandler({ + job, + taskId, + generatorInvocation, + interactiveTaskContext, + absolutePathToPreview, + telemetryContext: { + cliVersion: workspace.cliVersion, + orgId: projectConfig.organization, + automationMode: automationMode === true, + autoMerge: autoMerge === true, + skipIfNoDiff: skipIfNoDiff === true, + versionArg: version == null ? "none" : isAutoVersion(version) ? "auto" : "explicit", + versionBump: undefined, + replayConfigEnabled: replay?.enabled === true, + noReplayFlag: noReplay === true, + disableTelemetry: disableTelemetry === true + } + }); - let result = await pollJobAndReportStatus({ - job, - taskHandler, - taskId, - context: interactiveTaskContext - }); + result = await pollJobAndReportStatus({ + job, + taskHandler, + taskId, + context: interactiveTaskContext + }); + } // Fall back to the locally-resolved version when Fiddle doesn't echo it back // (e.g. GitHub push modes where no registry publish or release tag occurs). From 66f319f820b6b23b81103acfcb1b348be496d8c9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 20 Aug 2026 16:14:31 +0000 Subject: [PATCH 7/7] chore(cli): release 5.100.0 --- .../{unreleased => 5.100.0}/sdk-gen-api-backend.yml | 0 packages/cli/cli/versions.yml | 9 +++++++++ 2 files changed, 9 insertions(+) rename packages/cli/cli/changes/{unreleased => 5.100.0}/sdk-gen-api-backend.yml (100%) diff --git a/packages/cli/cli/changes/unreleased/sdk-gen-api-backend.yml b/packages/cli/cli/changes/5.100.0/sdk-gen-api-backend.yml similarity index 100% rename from packages/cli/cli/changes/unreleased/sdk-gen-api-backend.yml rename to packages/cli/cli/changes/5.100.0/sdk-gen-api-backend.yml diff --git a/packages/cli/cli/versions.yml b/packages/cli/cli/versions.yml index 7aa898ebd838..8446269e4af3 100644 --- a/packages/cli/cli/versions.yml +++ b/packages/cli/cli/versions.yml @@ -1,4 +1,13 @@ # yaml-language-server: $schema=../../../fern-versions-yml.schema.json +- version: 5.100.0 + changelogEntry: + - summary: | + Add an internal, default-disabled SDK generation route through sdk-gen-api. Preserve local + generation and non-SDK remote generators on their existing paths, and report unsupported + SDK migration features explicitly instead of silently falling back to Fiddle. + type: internal + createdAt: "2026-08-20" + irVersion: 67 - version: 5.99.1 changelogEntry: - summary: |