From 6e3c26f64cc9fba9dcfe08824d1127f1774d8e1b Mon Sep 17 00:00:00 2001 From: Jesse Rosalia Date: Wed, 18 Mar 2026 18:15:17 -0700 Subject: [PATCH 1/5] STJ migration phase 1: infrastructure, converters, and hand-written changes System.Text.Json migration for stripe-dotnet. This commit contains all hand-written (non-generated) changes: - Add STJ package references and multi-TFM support - STJ converter implementations (AnyOf, Expandable, DateTime, Enum, etc.) - Engine swap: deserialize/serialize paths now use System.Text.Json - Base entity/service/options classes updated with STJ attributes - Hand-written entity and service classes updated with STJ attributes - Request serialization migrated to STJ - All tests updated for STJ as primary deserializer - Wholesome tests for STJ attribute coverage Co-Authored-By: Claude Opus 4.6 Committed-By-Agent: claude --- .claude/CLAUDE.md | 50 +++ CHANGELOG.md | 21 ++ CODEGEN_VERSION | 2 +- OPENAPI_VERSION | 2 +- README.md | 3 + VERSION | 2 +- justfile | 3 + src/Stripe.net/Constants/Version.cs | 2 +- .../Accounts/AccountSettingsDeclineOn.cs | 6 - .../Entities/Balance/BalanceAmount.cs | 8 - .../Entities/Charges/ChargeLevel3LineItem.cs | 14 - .../ChargePaymentMethodDetailsBitcoin.cs | 14 - src/Stripe.net/Entities/Events/EventData.cs | 67 +++- src/Stripe.net/Entities/ExpandableField.cs | 4 - .../Invoices/InvoiceDiscountAmount.cs | 14 +- .../Entities/Invoices/InvoiceTaxAmount.cs | 20 +- .../Entities/OAuth/OAuthDeauthorize.cs | 4 - src/Stripe.net/Entities/OAuth/OAuthToken.cs | 16 - src/Stripe.net/Entities/Persons/Dob.cs | 8 - .../Entities/Products/PackageDimensions.cs | 10 - src/Stripe.net/Entities/Radar/Rules/Rule.cs | 10 - .../Entities/Reviews/ReviewLocation.cs | 15 +- src/Stripe.net/Entities/StripeError.cs | 35 +- src/Stripe.net/Entities/StripeList.cs | 12 - src/Stripe.net/Entities/StripeSearchResult.cs | 19 +- .../SubscriptionScheduleInvoiceSettings.cs | 7 +- ...ptionSchedulePhasePlanBillingThresholds.cs | 4 - .../Entities/V2/Core/EventNotification.cs | 18 +- .../V2/Core/EventNotificationReason.cs | 6 - .../V2/Core/EventNotificationReasonRequest.cs | 6 - .../V2/Core/EventNotificationRelatedObject.cs | 11 +- .../Entities/V2/Core/Events/Event.partial.cs | 16 +- .../V2/Core/Events/EventRelatedObject.cs | 8 - src/Stripe.net/Entities/V2/StripeList.cs | 10 - src/Stripe.net/Entities/_base/StripeEntity.cs | 99 +++++- src/Stripe.net/Entities/_common/Address.cs | 14 - .../Entities/_common/AddressJapan.cs | 4 - src/Stripe.net/Entities/_common/Amount.cs | 6 - src/Stripe.net/Entities/_common/Shipping.cs | 12 - .../_interfaces/IBalanceTransactionSource.cs | 4 - .../Entities/_interfaces/IExternalAccount.cs | 4 - .../Entities/_interfaces/IHasObject.cs | 4 - .../Entities/_interfaces/IPaymentSource.cs | 4 - .../Events/UnknownEventNotification.cs | 4 - .../FormEncoding/ContentEncoder.cs | 38 ++- .../FormEncoding/JsonEncodedContent.cs | 15 +- .../JsonConverters/DecimalStringConverter.cs | 37 ++ .../JsonConverters/Int64StringConverter.cs | 78 +++++ .../JsonConverters/STJAnyOfConverter.cs | 2 - .../JsonConverters/STJDefaultConverter.cs | 107 +++++- .../JsonConverters/STJEmptyableConverter.cs | 2 - .../STJEnumerableObjectConverter.cs | 16 +- .../JsonConverters/STJEventConverter.cs | 67 ++++ .../JsonConverters/STJEventDataConverter.cs | 67 ++++ .../STJExpandableFieldConverter.cs | 2 - .../STJMemberSerializationOptIn.cs | 48 --- .../JsonConverters/STJStringInt64Converter.cs | 39 +++ .../STJStripeEntityConverter.cs | 73 ++++ .../STJStripeObjectConverter.cs | 16 +- .../STJStripeOptionsConverter.cs | 36 ++ .../STJUnixDateTimeConverter.cs | 225 ++++++++---- .../JsonConverters/STJV2EventConverter.cs | 55 ++- .../STJV2EventNotificationConverter.cs | 44 ++- .../SerializablePropertyCache.cs | 155 ++++++++- .../Infrastructure/Public/AppInfo.cs | 10 - .../Infrastructure/Public/LiveApiRequestor.cs | 132 +++++--- .../Infrastructure/Public/RequestTelemetry.cs | 13 +- .../Infrastructure/Public/StripeClient.cs | 2 + .../Public/StripeConfiguration.cs | 40 ++- .../Infrastructure/Public/StripeException.cs | 8 +- .../Infrastructure/Public/StripeRequest.cs | 5 + .../Public/StripeTypeRegistry.cs | 3 + .../Public/SystemNetHttpClient.cs | 66 +++- .../BankAccounts/BankAccountCreateOptions.cs | 9 +- .../BankAccounts/BankAccountListOptions.cs | 8 +- .../Services/Cards/CardCreateOptions.cs | 13 +- .../Services/Cards/CardListOptions.cs | 8 +- .../Charges/ChargeSourceListOptions.cs | 4 - .../CreditNoteListPreviewLineItemsOptions.cs | 23 +- .../Services/Events/EventUtility.cs | 4 +- .../InvoiceUpdateInvoiceLineItemsOptions.cs | 24 -- .../Invoices/InvoiceLineItemListOptions.cs | 10 - .../Invoices/InvoiceListLineItemsOptions.cs | 10 - .../InvoiceUpcomingInvoiceItemOptions.cs | 36 +- .../OAuth/OAuthAuthorizeUrlOptions.cs | 20 -- .../OAuthAuthorizeUrlStripeUserOptions.cs | 56 --- .../Services/OAuth/OAuthDeauthorizeOptions.cs | 6 - .../Services/OAuth/OAuthTokenCreateOptions.cs | 14 - .../Prices/PriceTransformUsageOptions.cs | 6 - .../Products/PackageDimensionOptions.cs | 10 - .../Services/Skus/InventoryOptions.cs | 8 - .../Sources/SourceAcssDebitCreateOptions.cs | 8 - .../Services/Sources/SourceAttachOptions.cs | 6 - .../Sources/SourceAuBecsDebitCreateOptions.cs | 6 - .../Sources/SourceBancontactCreateOptions.cs | 4 - .../Services/Sources/SourceCreateOptions.cs | 57 +--- .../Sources/SourceIdealCreateOptions.cs | 4 - .../Sources/SourceKlarnaCreateOptions.cs | 56 --- .../Services/Sources/SourceListOptions.cs | 10 +- .../Sources/SourceSepaDebitCreateOptions.cs | 6 - .../Sources/SourceSofortCreateOptions.cs | 4 - .../SourceThreeDSecureCreateOptions.cs | 6 - ...scriptionScheduleInvoiceSettingsOptions.cs | 4 - ...hedulePhasePlanBillingThresholdsOptions.cs | 4 - ...iptionSchedulePhasePlanPriceDataOptions.cs | 15 +- ...edulePhasePlanPriceDataRecurringOptions.cs | 6 - .../TaxRates/TaxRatePercentageRangeOptions.cs | 13 +- src/Stripe.net/Services/_base/BaseOptions.cs | 8 +- src/Stripe.net/Services/_base/ListOptions.cs | 8 - .../Services/_base/SearchOptions.cs | 8 - src/Stripe.net/Services/_base/StringEnum.cs | 3 + .../Services/_base/V2/ListOptions.cs | 4 - .../Services/_common/AddressJapanOptions.cs | 4 - .../Services/_common/AddressOptions.cs | 14 - .../Services/_common/DateRangeOptions.cs | 13 +- .../Services/_common/MultipartFileContent.cs | 4 + .../Services/_common/RequestOptions.cs | 3 + .../Services/_refactor/SourceBankAccount.cs | 24 +- src/Stripe.net/Stripe.net.csproj | 11 +- .../Entities/AccountLinks/AccountLinkTest.cs | 4 +- .../Entities/Accounts/AccountTest.cs | 6 +- .../ApplePayDomains/ApplePayDomainTest.cs | 4 +- .../ApplicationFeeRefundTest.cs | 4 +- .../ApplicationFees/ApplicationFeeTest.cs | 6 +- .../Entities/Balance/BalanceTest.cs | 4 +- .../BalanceTransactionTest.cs | 6 +- .../Entities/BankAccounts/BankAccountTest.cs | 8 +- .../BillingPortal/Sessions/SessionTest.cs | 4 +- .../Entities/Capabilities/CapabilityTest.cs | 6 +- src/StripeTests/Entities/Cards/CardTest.cs | 6 +- .../Entities/Charges/ChargeTest.cs | 6 +- .../Entities/Checkout/SessionTest.cs | 6 +- .../Entities/CountrySpecs/CountrySpecTest.cs | 4 +- .../Entities/Coupons/CouponTest.cs | 4 +- .../Entities/CreditNotes/CreditNoteTest.cs | 6 +- .../CustomerBalanceTransactionTest.cs | 6 +- .../Entities/Customers/CustomerTest.cs | 8 +- .../Entities/DeserializationTest.cs | 37 +- .../Entities/Discounts/DiscountTest.cs | 4 +- .../Entities/Disputes/DisputeTest.cs | 6 +- .../EphemeralKeys/EphemeralKeyTest.cs | 4 +- src/StripeTests/Entities/Events/EventTest.cs | 9 +- .../ExternalAccounts/ExternalAccountTest.cs | 10 +- .../Entities/FileLinks/FileLinkTest.cs | 6 +- src/StripeTests/Entities/Files/FileTest.cs | 4 +- .../VerificationReportTest.cs | 4 +- .../VerificationSessionTest.cs | 6 +- .../Entities/InvoiceItems/InvoiceItemTest.cs | 6 +- .../Entities/Invoices/InvoiceLineItemTest.cs | 4 +- .../Entities/Invoices/InvoiceTest.cs | 26 +- .../Authorizations/AuthorizationTest.cs | 6 +- .../Issuing/Cardholders/CardholderTest.cs | 8 +- .../Entities/Issuing/Cards/CardTest.cs | 6 +- .../Entities/Issuing/Disputes/DisputeTest.cs | 6 +- .../Issuing/Transactions/TransactionTest.cs | 4 +- .../Entities/LineItems/LineItemTest.cs | 4 +- .../Entities/LoginLinks/LoginLinkTest.cs | 4 +- .../Entities/Mandates/MandateTest.cs | 6 +- .../PaymentIntents/PaymentIntentTest.cs | 14 +- .../PaymentMethods/PaymentMethodTest.cs | 6 +- .../Entities/Payouts/PayoutTest.cs | 6 +- .../Entities/Persons/PersonTest.cs | 6 +- src/StripeTests/Entities/Plans/PlanTest.cs | 6 +- src/StripeTests/Entities/Prices/PriceTest.cs | 6 +- .../Entities/Products/ProductTest.cs | 6 +- .../PromotionCodes/PromotionCodeTest.cs | 6 +- .../EarlyFraudWarningTest.cs | 6 +- .../Radar/ValueListItems/ValueListItemTest.cs | 4 +- .../Radar/ValueLists/ValueListTest.cs | 4 +- .../Entities/Refunds/RefundTest.cs | 6 +- .../Reporting/ReportRuns/ReportRunTest.cs | 4 +- .../Reporting/ReportTypes/ReportTypeTest.cs | 4 +- .../Entities/Reviews/ReviewTest.cs | 6 +- .../SetupAttempts/SetupAttemptTest.cs | 4 +- .../Entities/SetupIntents/SetupIntentTest.cs | 6 +- .../Entities/Sigma/ScheduledQueryRunTest.cs | 4 +- .../SourceMandateNotificationTest.cs | 4 +- .../Entities/Sources/SourceTest.cs | 4 +- .../SubscriptionItems/SubscriptionItemTest.cs | 4 +- .../SubscriptionScheduleTest.cs | 6 +- .../Subscriptions/SubscriptionTest.cs | 6 +- .../Entities/TaxCodes/TaxCodeTest.cs | 4 +- src/StripeTests/Entities/TaxIds/TaxIdTest.cs | 6 +- .../Entities/TaxRates/TaxRateTest.cs | 4 +- .../ConnectionTokens/ConnectionTokenTest.cs | 4 +- .../Terminal/Locations/LocationTest.cs | 4 +- .../Entities/Terminal/Readers/ReaderTest.cs | 17 +- src/StripeTests/Entities/Tokens/TokenTest.cs | 4 +- .../TransferReversals/TransferReversalTest.cs | 6 +- .../Entities/Transfers/TransferTest.cs | 6 +- .../WebhookEndpoints/WebhookEndpointTest.cs | 4 +- .../Entities/_base/StripeEntityTest.cs | 12 + src/StripeTests/Events/V2/EventTest.cs | 19 ++ src/StripeTests/Functional/TelemetryTest.cs | 1 - .../Functional/TelemetryTestUtils.cs | 16 +- .../Infrastructure/EnumDeserializationTest.cs | 34 +- .../FormEncoding/ContentEncoderTest.cs | 8 +- .../FormEncoding/FormEncoderTest.cs | 8 +- .../JsonConverters/AnyOfConverterTest.cs | 6 +- .../ExpandableFieldConverterTest.cs | 6 +- .../Int64StringConverterTest.cs | 52 +++ .../Infrastructure/Public/StripeClientTest.cs | 1 - .../Public/SystemNetHttpClientTest.cs | 132 +++++++- .../Infrastructure/SerializationTest.cs | 29 +- .../Infrastructure/StjDeserializationTest.cs | 51 --- .../TestData/TestObjectDateTime.cs | 2 - .../Infrastructure/TestData/TestOptions.cs | 32 +- .../events/event_pre_2017-05-25.json | 2 +- src/StripeTests/Services/AutoPagingTest.cs | 4 +- .../Services/_base/BaseOptionsTest.cs | 19 +- src/StripeTests/Services/_base/ServiceTest.cs | 2 + src/StripeTests/StripeTests.csproj | 2 + .../ClassesHaveAllNecessaryJsonAttributes.cs | 9 +- ...ectJsonConvertersForEnumerableItemTypes.cs | 2 - .../CorrectJsonConvertersForTypes.cs | 7 + ...nConvertersForTypesWithNonPublicMembers.cs | 13 +- ...CorrectSystemTextJsonConvertersForTypes.cs | 2 - .../DontSerializeNullDeletedAttrs.cs | 4 - .../Wholesome/JsonNamesMatchPropertyNames.cs | 5 +- ...dSystemTextJsonDeserializeTheSameObject.cs | 319 ++++++++++++++++++ ...oftAndSystemTextJsonOutputTheSameObject.cs | 21 +- ...ropertiesHaveAllNecessaryJsonAttributes.cs | 23 +- .../Wholesome/SystemTextJsonTestUtils.cs | 18 +- 223 files changed, 2329 insertions(+), 1572 deletions(-) create mode 100644 .claude/CLAUDE.md create mode 100644 src/Stripe.net/Infrastructure/JsonConverters/DecimalStringConverter.cs create mode 100644 src/Stripe.net/Infrastructure/JsonConverters/Int64StringConverter.cs create mode 100644 src/Stripe.net/Infrastructure/JsonConverters/STJEventConverter.cs create mode 100644 src/Stripe.net/Infrastructure/JsonConverters/STJEventDataConverter.cs delete mode 100644 src/Stripe.net/Infrastructure/JsonConverters/STJMemberSerializationOptIn.cs create mode 100644 src/Stripe.net/Infrastructure/JsonConverters/STJStringInt64Converter.cs create mode 100644 src/Stripe.net/Infrastructure/JsonConverters/STJStripeEntityConverter.cs create mode 100644 src/Stripe.net/Infrastructure/JsonConverters/STJStripeOptionsConverter.cs create mode 100644 src/StripeTests/Infrastructure/JsonConverters/Int64StringConverterTest.cs delete mode 100644 src/StripeTests/Infrastructure/StjDeserializationTest.cs create mode 100644 src/StripeTests/Wholesome/NewtonsoftAndSystemTextJsonDeserializeTheSameObject.cs diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md new file mode 100644 index 0000000000..8b47500c6e --- /dev/null +++ b/.claude/CLAUDE.md @@ -0,0 +1,50 @@ +# stripe-dotnet + +## Testing + +- Run all tests: `just test` (auto-installs correct .NET version) +- Run a specific test: `just test-one TestClassName` or `just test-one FullyQualifiedName` + +## Formatting + +- Format: `just format` +- Format check: `just format-check` +- Uses `dotnet format` (whitespace + analyzers) + +## Key Locations + +- HTTP client interface: `src/Stripe.net/Infrastructure/Public/IHttpClient.cs` +- HTTP implementation: `src/Stripe.net/Infrastructure/Public/SystemNetHttpClient.cs` +- Main client class: `src/Stripe.net/Infrastructure/Public/StripeClient.cs` +- Client options: `src/Stripe.net/Infrastructure/Public/StripeClientOptions.cs` +- Request building: `src/Stripe.net/Infrastructure/Public/StripeRequest.cs` +- API requestor: `src/Stripe.net/Infrastructure/Public/LiveApiRequestor.cs` +- Version: `src/Stripe.net/Constants/Version.cs` +- Tests: `src/StripeTests/` + +## Generated Code + +- Files containing `File generated from our OpenAPI spec` at the top are generated; do not edit. Similarly, any code block starting with `The beginning of the section generated from our OpenAPI spec` is generated and should not be edited directly. + - If something in a generated file/range needs to be updated, add a summary of the change to your report but don't attempt to edit it directly. +- The `Infrastructure/` directory is NOT generated. + +## Conventions + +- Uses .NET `System.Net.Http.HttpClient` +- Multi-target framework (net461+, net6.0+, etc.) +- Solution file: `src/Stripe.net.sln` +- .NET version managed via mise +- All code must run on all supported .NET versions (full list in the test section of @.github/workflows/ci.yml) +- Work is not complete until `just test`, `just format` complete successfully. + +### Comments + +- Comments MUST only be used to: + 1. Document a function + 2. Explain the WHY of a piece of code + 3. Explain a particularly complicated piece of code +- Comments NEVER should be used to: + 1. Say what used to be there. That's no longer relevant! + 2. Explain the WHAT of a piece of code (unless it's very non-obvious) + +It's ok not to put comments on/in a function if their addition wouldn't meaningfully clarify anything. diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d6aab68e6..6315daefc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## 50.4.1 - 2026-03-06 +* [#3313](https://github.com/stripe/stripe-dotnet/pull/3313) Add Stripe-Request-Trigger header +* [#3310](https://github.com/stripe/stripe-dotnet/pull/3310) Add agent information to UserAgent + +## 50.4.0 - 2026-02-25 +This release changes the pinned API version to `2026-02-25.clover`. + +* [#3304](https://github.com/stripe/stripe-dotnet/pull/3304) Update generated code + * Add support for new resources `Reserve.Hold`, `Reserve.Plan`, and `Reserve.Release` + * Add support for `Location` and `Reader` on `Charge.PaymentMethodDetails.CardPresent`, `Charge.PaymentMethodDetails.InteracPresent`, `ConfirmationToken.PaymentMethodPreview.Card.GeneratedFrom.PaymentMethodDetails.CardPresent`, `PaymentAttemptRecord.PaymentMethodDetails.CardPresent`, `PaymentAttemptRecord.PaymentMethodDetails.InteracPresent`, `PaymentMethod.Card.GeneratedFrom.PaymentMethodDetails.CardPresent`, `PaymentRecord.PaymentMethodDetails.CardPresent`, and `PaymentRecord.PaymentMethodDetails.InteracPresent` + * Add support for `DisplayName` and `ServiceUserNumber` on `Mandate.PaymentMethodDetails.BacsDebit` + * Add support for `TransactionPurpose` on `PaymentIntent.PaymentMethodOptions.UsBankAccount` and `PaymentIntentPaymentMethodOptionsUsBankAccountOptions` + * Add support for `OptionalItems` on `PaymentLinkUpdateOptions` + * Remove support for unused `CardIssuerDecline` on `Radar.PaymentEvaluation.Insights` + * Add support for `PaymentBehavior` on `SubscriptionItemDeleteOptions` + * Add support for `Lk` on `Tax.Registration.CountryOptions` and `TaxRegistrationCountryOptionsOptions` + * Add support for `Cellular` and `StripeS710` on `Terminal.ConfigurationCreateOptions`, `Terminal.ConfigurationUpdateOptions`, and `Terminal.Configuration` + * Add support for snapshot events `ReserveHoldCreated` and `ReserveHoldUpdated` with resource `Reserve.Hold` + * Add support for snapshot events `ReservePlanCreated`, `ReservePlanDisabled`, `ReservePlanExpired`, and `ReservePlanUpdated` with resource `Reserve.Plan` + * Add support for snapshot event `ReserveReleaseCreated` with resource `Reserve.Release` + ## 50.3.0 - 2026-01-28 This release changes the pinned API version to `2026-01-28.clover`. diff --git a/CODEGEN_VERSION b/CODEGEN_VERSION index 5a8d600ad1..17557a68f2 100644 --- a/CODEGEN_VERSION +++ b/CODEGEN_VERSION @@ -1 +1 @@ -45d723936ebab9668b6996394720dcf4a2436671 \ No newline at end of file +e65e48569f6dfad2d5f1b58018017856520c3ae6 \ No newline at end of file diff --git a/OPENAPI_VERSION b/OPENAPI_VERSION index d88d05d5c9..58dae79358 100644 --- a/OPENAPI_VERSION +++ b/OPENAPI_VERSION @@ -1 +1 @@ -v2159 \ No newline at end of file +v2186 \ No newline at end of file diff --git a/README.md b/README.md index 3c48162008..f7cd2f5a35 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ [![Build Status](https://github.com/stripe/stripe-dotnet/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/stripe/stripe-dotnet/actions?query=branch%3Amaster) [![Coverage Status](https://coveralls.io/repos/github/stripe/stripe-dotnet/badge.svg?branch=master)](https://coveralls.io/github/stripe/stripe-dotnet?branch=master) +> [!TIP] +> Want to chat live with Stripe engineers? Join us on our [Discord server](https://stripe.com/go/discord/dotnet). + The official [Stripe][stripe] .NET library, supporting .NET Standard 2.0+, .NET Core 5+, and .NET Framework 4.6.2+. ## Installation diff --git a/VERSION b/VERSION index a58784a019..2e50c87d07 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -50.3.0 +50.4.1 diff --git a/justfile b/justfile index 0747e93943..74ec1f8af3 100644 --- a/justfile +++ b/justfile @@ -5,6 +5,9 @@ import? '../sdk-codegen/utils.just' _default: just --list --unsorted +# ⭐ run format and tests to prepare for CI +prepare: format test + # _supported_dotnet_versions is built from the ... in the Stripe.net.csproj _supported_dotnet_versions := ` sed -n 's/.*\(.*\)<\/TargetFrameworks>.*/\1/p' src/Stripe.net/Stripe.net.csproj \ diff --git a/src/Stripe.net/Constants/Version.cs b/src/Stripe.net/Constants/Version.cs index 1a46d07241..70d41aa71e 100644 --- a/src/Stripe.net/Constants/Version.cs +++ b/src/Stripe.net/Constants/Version.cs @@ -2,6 +2,6 @@ namespace Stripe { internal class Version { - public const string Current = "50.3.0"; + public const string Current = "50.4.1"; } } \ No newline at end of file diff --git a/src/Stripe.net/Entities/Accounts/AccountSettingsDeclineOn.cs b/src/Stripe.net/Entities/Accounts/AccountSettingsDeclineOn.cs index 067ead9e3f..f2546a5bed 100644 --- a/src/Stripe.net/Entities/Accounts/AccountSettingsDeclineOn.cs +++ b/src/Stripe.net/Entities/Accounts/AccountSettingsDeclineOn.cs @@ -1,22 +1,16 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class AccountSettingsDeclineOn : StripeEntity { [JsonProperty("avs_failure")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("avs_failure")] -#endif public bool AvsFailure { get; set; } [JsonProperty("cvc_failure")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("cvc_failure")] -#endif public bool CvcFailure { get; set; } } } diff --git a/src/Stripe.net/Entities/Balance/BalanceAmount.cs b/src/Stripe.net/Entities/Balance/BalanceAmount.cs index d69ddf4493..71b1e20d0d 100644 --- a/src/Stripe.net/Entities/Balance/BalanceAmount.cs +++ b/src/Stripe.net/Entities/Balance/BalanceAmount.cs @@ -2,28 +2,20 @@ namespace Stripe { using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class BalanceAmount : StripeEntity { [JsonProperty("amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("amount")] -#endif public long Amount { get; set; } [JsonProperty("currency")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("currency")] -#endif public string Currency { get; set; } [JsonProperty("source_types")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("source_types")] -#endif public Dictionary SourceTypes { get; set; } } } diff --git a/src/Stripe.net/Entities/Charges/ChargeLevel3LineItem.cs b/src/Stripe.net/Entities/Charges/ChargeLevel3LineItem.cs index a582b62c15..bdd65ecb9b 100644 --- a/src/Stripe.net/Entities/Charges/ChargeLevel3LineItem.cs +++ b/src/Stripe.net/Entities/Charges/ChargeLevel3LineItem.cs @@ -1,46 +1,32 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class ChargeLevel3LineItem : StripeEntity { [JsonProperty("discount_amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("discount_amount")] -#endif public long? DiscountAmount { get; set; } [JsonProperty("product_code")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("product_code")] -#endif public string ProductCode { get; set; } [JsonProperty("product_description")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("product_description")] -#endif public string ProductDescription { get; set; } [JsonProperty("quantity")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("quantity")] -#endif public long? Quantity { get; set; } [JsonProperty("tax_amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("tax_amount")] -#endif public long? TaxAmount { get; set; } [JsonProperty("unit_cost")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("unit_cost")] -#endif public long? UnitCost { get; set; } } } diff --git a/src/Stripe.net/Entities/Charges/ChargePaymentMethodDetailsBitcoin.cs b/src/Stripe.net/Entities/Charges/ChargePaymentMethodDetailsBitcoin.cs index 06397073ba..f6ac3328ef 100644 --- a/src/Stripe.net/Entities/Charges/ChargePaymentMethodDetailsBitcoin.cs +++ b/src/Stripe.net/Entities/Charges/ChargePaymentMethodDetailsBitcoin.cs @@ -1,46 +1,32 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class ChargePaymentMethodDetailsBitcoin : StripeEntity { [JsonProperty("address")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("address")] -#endif public string Address { get; set; } [JsonProperty("amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("amount")] -#endif public long? Amount { get; set; } [JsonProperty("amount_charged")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("amount_charged")] -#endif public long? AmountCharged { get; set; } [JsonProperty("amount_received")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("amount_received")] -#endif public long? AmountReceived { get; set; } [JsonProperty("amount_returned")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("amount_returned")] -#endif public long? AmountReturned { get; set; } [JsonProperty("refund_address")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("refund_address")] -#endif public string RefundAddress { get; set; } } } diff --git a/src/Stripe.net/Entities/Events/EventData.cs b/src/Stripe.net/Entities/Events/EventData.cs index e22a8442ff..9686eb5597 100644 --- a/src/Stripe.net/Entities/Events/EventData.cs +++ b/src/Stripe.net/Entities/Events/EventData.cs @@ -2,12 +2,16 @@ namespace Stripe { using Newtonsoft.Json; using Stripe.Infrastructure; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif + [STJS.JsonConverter(typeof(STJEventDataConverter))] public class EventData : StripeEntity { + private string rawObjectJson; + private dynamic rawObject; + private string previousAttributesJson; + private dynamic previousAttributes; + /// /// Object containing the API resource relevant to the event. For example, an /// invoice.created event will have a full invoice object () as @@ -15,9 +19,7 @@ public class EventData : StripeEntity /// [JsonProperty("object")] [JsonConverter(typeof(StripeObjectConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("object")] -#endif public IHasObject Object { get; set; } /// @@ -25,10 +27,26 @@ public class EventData : StripeEntity /// values (sent along only with *.updated events). /// [JsonProperty("previous_attributes")] -#if NET6_0_OR_GREATER - [STJS.JsonPropertyName("previous_attributes")] -#endif - public dynamic PreviousAttributes { get; set; } + [STJS.JsonIgnore] + [NoSystemTextJsonAttributesNeeded("STJEventConverter handles PreviousAttributes separately via SetPreviousAttributesJson")] + public dynamic PreviousAttributes + { + get + { + if (this.previousAttributes == null && this.previousAttributesJson != null) + { + this.previousAttributes = Newtonsoft.Json.Linq.JToken.Parse(this.previousAttributesJson); + } + + return this.previousAttributes; + } + + set + { + this.previousAttributes = value; + this.previousAttributesJson = null; + } + } /// /// This contains the same data as , but untyped. This is @@ -36,9 +54,36 @@ public class EventData : StripeEntity /// library does not have a concrete type. /// [JsonIgnore] -#if NET6_0_OR_GREATER [STJS.JsonIgnore] -#endif - public dynamic RawObject { get; set; } + public dynamic RawObject + { + get + { + if (this.rawObject == null && this.rawObjectJson != null) + { + this.rawObject = Newtonsoft.Json.Linq.JToken.Parse(this.rawObjectJson); + } + + return this.rawObject; + } + + set + { + this.rawObject = value; + this.rawObjectJson = null; + } + } + + internal void SetRawObjectJson(string json) + { + this.rawObjectJson = json; + this.rawObject = null; + } + + internal void SetPreviousAttributesJson(string json) + { + this.previousAttributesJson = json; + this.previousAttributes = null; + } } } diff --git a/src/Stripe.net/Entities/ExpandableField.cs b/src/Stripe.net/Entities/ExpandableField.cs index 4f411a0ff9..73147f63ec 100644 --- a/src/Stripe.net/Entities/ExpandableField.cs +++ b/src/Stripe.net/Entities/ExpandableField.cs @@ -1,16 +1,12 @@ namespace Stripe { using System; -#if NET6_0_OR_GREATER using Stripe.Infrastructure; using STJS = System.Text.Json.Serialization; -#endif /// Represents a generic expandable field. /// Type of the field when expanded. -#if NET6_0_OR_GREATER [STJS.JsonConverter(typeof(STJExpandableFieldConverterFactory))] -#endif public class ExpandableField : IExpandableField where T : IHasId { diff --git a/src/Stripe.net/Entities/Invoices/InvoiceDiscountAmount.cs b/src/Stripe.net/Entities/Invoices/InvoiceDiscountAmount.cs index 1c32cb83fd..364fd34393 100644 --- a/src/Stripe.net/Entities/Invoices/InvoiceDiscountAmount.cs +++ b/src/Stripe.net/Entities/Invoices/InvoiceDiscountAmount.cs @@ -2,27 +2,19 @@ namespace Stripe { using Newtonsoft.Json; using Stripe.Infrastructure; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif -#if NET6_0_OR_GREATER - [STJS.JsonConverter(typeof(STJMemberSerializationOptIn))] -#endif + [STJS.JsonConverter(typeof(STJStripeEntityConverter))] public class InvoiceDiscountAmount : StripeEntity { [JsonProperty("amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("amount")] -#endif public long Amount { get; set; } #region Expandable Discount [JsonIgnore] -#if NET6_0_OR_GREATER [STJS.JsonIgnore] -#endif public string DiscountId { get => this.InternalDiscount?.Id; @@ -30,9 +22,7 @@ public string DiscountId } [JsonIgnore] -#if NET6_0_OR_GREATER [STJS.JsonIgnore] -#endif public Discount Discount { get => this.InternalDiscount?.ExpandedObject; @@ -41,10 +31,8 @@ public Discount Discount [JsonProperty("discount")] [JsonConverter(typeof(ExpandableFieldConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("discount")] [STJS.JsonConverter(typeof(STJExpandableFieldConverter))] -#endif internal ExpandableField InternalDiscount { get; set; } #endregion } diff --git a/src/Stripe.net/Entities/Invoices/InvoiceTaxAmount.cs b/src/Stripe.net/Entities/Invoices/InvoiceTaxAmount.cs index 6eed36a722..6512189ca5 100644 --- a/src/Stripe.net/Entities/Invoices/InvoiceTaxAmount.cs +++ b/src/Stripe.net/Entities/Invoices/InvoiceTaxAmount.cs @@ -2,31 +2,23 @@ namespace Stripe { using Newtonsoft.Json; using Stripe.Infrastructure; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif -#if NET6_0_OR_GREATER - [STJS.JsonConverter(typeof(STJMemberSerializationOptIn))] -#endif + [STJS.JsonConverter(typeof(STJStripeEntityConverter))] public class InvoiceTaxAmount : StripeEntity { /// /// The amount, in cents (or local equivalent), of the tax. /// [JsonProperty("amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("amount")] -#endif public long Amount { get; set; } /// /// Whether this tax amount is inclusive or exclusive. /// [JsonProperty("inclusive")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("inclusive")] -#endif public bool Inclusive { get; set; } #region Expandable TaxRate @@ -36,9 +28,7 @@ public class InvoiceTaxAmount : StripeEntity /// The tax rate that was applied to get this tax amount. /// [JsonIgnore] -#if NET6_0_OR_GREATER [STJS.JsonIgnore] -#endif public string TaxRateId { get => this.InternalTaxRate?.Id; @@ -52,9 +42,7 @@ public string TaxRateId /// For more information, see the expand documentation. /// [JsonIgnore] -#if NET6_0_OR_GREATER [STJS.JsonIgnore] -#endif public TaxRate TaxRate { get => this.InternalTaxRate?.ExpandedObject; @@ -63,10 +51,8 @@ public TaxRate TaxRate [JsonProperty("tax_rate")] [JsonConverter(typeof(ExpandableFieldConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("tax_rate")] [STJS.JsonConverter(typeof(STJExpandableFieldConverter))] -#endif internal ExpandableField InternalTaxRate { get; set; } #endregion @@ -80,18 +66,14 @@ public TaxRate TaxRate /// standard_rated, taxable_basis_reduced, or zero_rated. /// [JsonProperty("taxability_reason")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("taxability_reason")] -#endif public string TaxabilityReason { get; set; } /// /// The amount on which tax is calculated, in cents (or local equivalent). /// [JsonProperty("taxable_amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("taxable_amount")] -#endif public long? TaxableAmount { get; set; } } } diff --git a/src/Stripe.net/Entities/OAuth/OAuthDeauthorize.cs b/src/Stripe.net/Entities/OAuth/OAuthDeauthorize.cs index ce27d265c5..62b60730f5 100644 --- a/src/Stripe.net/Entities/OAuth/OAuthDeauthorize.cs +++ b/src/Stripe.net/Entities/OAuth/OAuthDeauthorize.cs @@ -1,9 +1,7 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class OAuthDeauthorize : StripeEntity { @@ -13,9 +11,7 @@ public class OAuthDeauthorize : StripeEntity /// returned, the revocation was successful. /// [JsonProperty("stripe_user_id")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("stripe_user_id")] -#endif public string StripeUserId { get; set; } } } diff --git a/src/Stripe.net/Entities/OAuth/OAuthToken.cs b/src/Stripe.net/Entities/OAuth/OAuthToken.cs index 7bd8e99a69..9ca96e891a 100644 --- a/src/Stripe.net/Entities/OAuth/OAuthToken.cs +++ b/src/Stripe.net/Entities/OAuth/OAuthToken.cs @@ -2,9 +2,7 @@ namespace Stripe { using System; using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class OAuthToken : StripeEntity { @@ -27,9 +25,7 @@ public class OAuthToken : StripeEntity /// [Obsolete("Use StripeUserId instead.")] [JsonProperty("access_token")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("access_token")] -#endif public string AccessToken { get; set; } /// @@ -41,9 +37,7 @@ public class OAuthToken : StripeEntity /// Depends on the mode of the secret API key used to make the request. /// [JsonProperty("livemode")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("livemode")] -#endif public bool Livemode { get; set; } /// @@ -58,9 +52,7 @@ public class OAuthToken : StripeEntity /// [Obsolete("Use StripeUserId instead.")] [JsonProperty("refresh_token")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("refresh_token")] -#endif public string RefreshToken { get; set; } /// @@ -68,9 +60,7 @@ public class OAuthToken : StripeEntity /// and scope parameter. /// [JsonProperty("scope")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("scope")] -#endif public string Scope { get; set; } /// @@ -84,25 +74,19 @@ public class OAuthToken : StripeEntity /// [Obsolete("Use StripeUserId instead.")] [JsonProperty("stripe_publishable_key")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("stripe_publishable_key")] -#endif public string StripePublishableKey { get; set; } /// /// The unique id of the account you have been granted access to, as a string. /// [JsonProperty("stripe_user_id")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("stripe_user_id")] -#endif public string StripeUserId { get; set; } /// Will always have a value of bearer. [JsonProperty("token_type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("token_type")] -#endif public string TokenType { get; set; } } } diff --git a/src/Stripe.net/Entities/Persons/Dob.cs b/src/Stripe.net/Entities/Persons/Dob.cs index 41cf54c3c2..4170c3e4a6 100644 --- a/src/Stripe.net/Entities/Persons/Dob.cs +++ b/src/Stripe.net/Entities/Persons/Dob.cs @@ -1,28 +1,20 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class Dob : StripeEntity { [JsonProperty("day")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("day")] -#endif public long? Day { get; set; } [JsonProperty("month")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("month")] -#endif public long? Month { get; set; } [JsonProperty("year")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("year")] -#endif public long? Year { get; set; } } } diff --git a/src/Stripe.net/Entities/Products/PackageDimensions.cs b/src/Stripe.net/Entities/Products/PackageDimensions.cs index c10555960f..e26e0a9485 100644 --- a/src/Stripe.net/Entities/Products/PackageDimensions.cs +++ b/src/Stripe.net/Entities/Products/PackageDimensions.cs @@ -1,34 +1,24 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class PackageDimensions : StripeEntity { [JsonProperty("height")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("height")] -#endif public decimal? Height { get; set; } [JsonProperty("length")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("length")] -#endif public decimal? Length { get; set; } [JsonProperty("weight")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("weight")] -#endif public decimal? Weight { get; set; } [JsonProperty("width")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("width")] -#endif public decimal? Width { get; set; } } } diff --git a/src/Stripe.net/Entities/Radar/Rules/Rule.cs b/src/Stripe.net/Entities/Radar/Rules/Rule.cs index a1abac682b..f715d9800b 100644 --- a/src/Stripe.net/Entities/Radar/Rules/Rule.cs +++ b/src/Stripe.net/Entities/Radar/Rules/Rule.cs @@ -1,35 +1,25 @@ namespace Stripe.Radar { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class Rule : StripeEntity, IHasId { [JsonProperty("id")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("id")] -#endif public string Id { get; set; } [JsonProperty("action")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("action")] -#endif public string Action { get; set; } [JsonProperty("deleted", NullValueHandling = NullValueHandling.Ignore)] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("deleted")] [STJS.JsonIgnore(Condition = STJS.JsonIgnoreCondition.WhenWritingNull)] -#endif public bool? Deleted { get; set; } [JsonProperty("predicate")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("predicate")] -#endif public string Predicate { get; set; } } } diff --git a/src/Stripe.net/Entities/Reviews/ReviewLocation.cs b/src/Stripe.net/Entities/Reviews/ReviewLocation.cs index 0a20316120..79b48b59ec 100644 --- a/src/Stripe.net/Entities/Reviews/ReviewLocation.cs +++ b/src/Stripe.net/Entities/Reviews/ReviewLocation.cs @@ -2,42 +2,29 @@ namespace Stripe { using System; using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; public class ReviewLocation : StripeEntity { [JsonProperty("city")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("city")] -#endif public string City { get; set; } [JsonProperty("country")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("country")] -#endif public string Country { get; set; } [JsonProperty("latitude")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("latitude")] -#endif public decimal? Latitude { get; set; } [JsonProperty("longitude")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("longitude")] -#endif public decimal? Longitude { get; set; } [JsonProperty("region")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("region")] -#endif public string Region { get; set; } } } diff --git a/src/Stripe.net/Entities/StripeError.cs b/src/Stripe.net/Entities/StripeError.cs index b1851dfc45..be506d0a7f 100644 --- a/src/Stripe.net/Entities/StripeError.cs +++ b/src/Stripe.net/Entities/StripeError.cs @@ -1,11 +1,8 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; public class StripeError : StripeEntity { @@ -15,9 +12,7 @@ public class StripeError : StripeEntity /// For card errors, the ID of the failed charge. [JsonProperty("charge")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("charge")] -#endif public string Charge { get; set; } /// @@ -25,9 +20,7 @@ public class StripeError : StripeEntity /// error code reported. /// [JsonProperty("code")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("code")] -#endif public string Code { get; set; } /// @@ -36,9 +29,7 @@ public class StripeError : StripeEntity /// decline. /// [JsonProperty("decline_code")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("decline_code")] -#endif public string DeclineCode { get; set; } /// @@ -46,9 +37,7 @@ public class StripeError : StripeEntity /// code reported. /// [JsonProperty("doc_url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("doc_url")] -#endif public string DocUrl { get; set; } /// @@ -56,9 +45,7 @@ public class StripeError : StripeEntity /// messages can be shown to your users. /// [JsonProperty("message")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("message")] -#endif public string Message { get; set; } /// @@ -66,9 +53,7 @@ public class StripeError : StripeEntity /// you can use this to display a message near the correct form field. /// [JsonProperty("param")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("param")] -#endif public string Param { get; set; } /// @@ -76,9 +61,7 @@ public class StripeError : StripeEntity /// involving a . /// [JsonProperty("payment_intent")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("payment_intent")] -#endif public PaymentIntent PaymentIntent { get; set; } /// @@ -86,9 +69,7 @@ public class StripeError : StripeEntity /// involving a . /// [JsonProperty("payment_method")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("payment_method")] -#endif public PaymentMethod PaymentMethod { get; set; } /// @@ -96,18 +77,14 @@ public class StripeError : StripeEntity /// a problem. This field is only populated for invoice-related errors. /// [JsonProperty("payment_method_type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("payment_method_type")] -#endif public string PaymentMethodType { get; set; } /// /// A URL to the request log entry in your dashboard. /// [JsonProperty("request_log_url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("request_log_url")] -#endif public string RequestLogUrl { get; set; } /// @@ -115,9 +92,7 @@ public class StripeError : StripeEntity /// involving a . /// [JsonProperty("setup_intent")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("setup_intent")] -#endif public SetupIntent SetupIntent { get; set; } /// @@ -125,9 +100,7 @@ public class StripeError : StripeEntity /// [JsonProperty("source")] [JsonConverter(typeof(StripeObjectConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("source")] -#endif public IPaymentSource Source { get; set; } /// @@ -135,9 +108,7 @@ public class StripeError : StripeEntity /// idempotency_error, or invalid_request_error. /// [JsonProperty("type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("type")] -#endif public string Type { get; set; } /* @@ -145,15 +116,11 @@ public class StripeError : StripeEntity */ [JsonProperty("error")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("error")] -#endif public string Error { get; set; } [JsonProperty("error_description")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("error_description")] -#endif public string ErrorDescription { get; set; } } } diff --git a/src/Stripe.net/Entities/StripeList.cs b/src/Stripe.net/Entities/StripeList.cs index 8839942022..79f086d618 100644 --- a/src/Stripe.net/Entities/StripeList.cs +++ b/src/Stripe.net/Entities/StripeList.cs @@ -4,32 +4,24 @@ namespace Stripe using System.Collections.Generic; using Newtonsoft.Json; using Stripe.Infrastructure; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif [JsonObject] -#if NET6_0_OR_GREATER [STJS.JsonConverter(typeof(STJEnumerableObjectConverter))] -#endif public class StripeList : StripeEntity>, IHasObject, IEnumerable { /// /// A string describing the object type returned. /// [JsonProperty("object")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("object")] -#endif public string Object { get; set; } /// /// A list containing the actual response elements, paginated by any request parameters. /// [JsonProperty("data", ItemConverterType = typeof(StripeObjectConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("data")] // STJ determines the conversion from annotations on the inner type -#endif public List Data { get; set; } /// @@ -37,18 +29,14 @@ public class StripeList : StripeEntity>, IHasObject, IEnumerabl /// this set comprises the end of the list. /// [JsonProperty("has_more")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("has_more")] -#endif public bool HasMore { get; set; } /// /// The URL for accessing this list. /// [JsonProperty("url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("url")] -#endif public string Url { get; set; } public IEnumerator GetEnumerator() diff --git a/src/Stripe.net/Entities/StripeSearchResult.cs b/src/Stripe.net/Entities/StripeSearchResult.cs index 65325ae5bb..a6d2ba2c2c 100644 --- a/src/Stripe.net/Entities/StripeSearchResult.cs +++ b/src/Stripe.net/Entities/StripeSearchResult.cs @@ -3,34 +3,25 @@ namespace Stripe using System.Collections; using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; [JsonObject] -#if NET6_0_OR_GREATER [STJS.JsonConverter(typeof(STJEnumerableObjectConverter))] -#endif public class StripeSearchResult : StripeEntity>, IHasObject, IEnumerable { /// /// A string describing the object type returned. /// [JsonProperty("object")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("object")] -#endif public string Object { get; set; } /// /// A list containing the actual response elements, paginated by any request parameters. /// [JsonProperty("data", ItemConverterType = typeof(StripeObjectConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("data")] // STJ determines the conversion from annotations on the inner type -#endif public List Data { get; set; } /// @@ -38,27 +29,21 @@ public class StripeSearchResult : StripeEntity>, IHasOb /// this set comprises the end of the list. /// [JsonProperty("has_more")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("has_more")] -#endif public bool HasMore { get; set; } /// /// The URL for accessing this list. /// [JsonProperty("url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("url")] -#endif public string Url { get; set; } /// /// The URL for accessing the next page in search results. /// [JsonProperty("next_page")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("next_page")] -#endif public string NextPage { get; set; } /// @@ -66,9 +51,7 @@ public class StripeSearchResult : StripeEntity>, IHasOb /// Only available when contains "total_count". /// [JsonProperty("total_count")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("total_count")] -#endif public long? TotalCount { get; set; } public IEnumerator GetEnumerator() diff --git a/src/Stripe.net/Entities/SubscriptionSchedules/SubscriptionScheduleInvoiceSettings.cs b/src/Stripe.net/Entities/SubscriptionSchedules/SubscriptionScheduleInvoiceSettings.cs index 2587b6b2f4..9b5ffa5aaf 100644 --- a/src/Stripe.net/Entities/SubscriptionSchedules/SubscriptionScheduleInvoiceSettings.cs +++ b/src/Stripe.net/Entities/SubscriptionSchedules/SubscriptionScheduleInvoiceSettings.cs @@ -3,18 +3,13 @@ namespace Stripe using System; using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; public class SubscriptionScheduleInvoiceSettings : StripeEntity { [JsonProperty("days_until_due")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("days_until_due")] -#endif public long? DaysUntilDue { get; set; } } } diff --git a/src/Stripe.net/Entities/SubscriptionSchedules/SubscriptionSchedulePhasePlanBillingThresholds.cs b/src/Stripe.net/Entities/SubscriptionSchedules/SubscriptionSchedulePhasePlanBillingThresholds.cs index 256073294a..95fb67c9eb 100644 --- a/src/Stripe.net/Entities/SubscriptionSchedules/SubscriptionSchedulePhasePlanBillingThresholds.cs +++ b/src/Stripe.net/Entities/SubscriptionSchedules/SubscriptionSchedulePhasePlanBillingThresholds.cs @@ -1,16 +1,12 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SubscriptionSchedulePhasePlanBillingThresholds : StripeEntity { [JsonProperty("usage_gte")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("usage_gte")] -#endif public long? UsageGte { get; set; } } } diff --git a/src/Stripe.net/Entities/V2/Core/EventNotification.cs b/src/Stripe.net/Entities/V2/Core/EventNotification.cs index 3422bc6da2..954ce83ea1 100644 --- a/src/Stripe.net/Entities/V2/Core/EventNotification.cs +++ b/src/Stripe.net/Entities/V2/Core/EventNotification.cs @@ -7,53 +7,41 @@ namespace Stripe.V2.Core using System.Threading.Tasks; using Newtonsoft.Json; using Stripe.Infrastructure; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif /// /// An EventNotification, which is delivered to an Event Destination to tell you that an Event has happened. /// [JsonConverter(typeof(V2EventNotificationConverter))] -#if NET6_0_OR_GREATER [STJS.JsonConverter(typeof(STJV2EventNotificationConverter))] -#endif public class EventNotification { /// /// Unique identifier for the event. /// [JsonProperty("id")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("id")] -#endif public string Id { get; internal set; } /// /// The type of the event. /// [JsonProperty("type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("type")] -#endif public string Type { get; internal set; } /// /// Time at which the object was created. /// [JsonProperty("created")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("created")] -#endif public DateTime Created { get; internal set; } /// /// Livemode indicates if the event is from a production(true) or test(false) account. /// [JsonProperty("livemode")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("livemode")] -#endif public bool Livemode { get; internal set; } #nullable enable @@ -61,18 +49,14 @@ public class EventNotification /// [Optional] Reason for the event. /// [JsonProperty("reason")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("reason")] -#endif public EventNotificationReason? Reason { get; internal set; } /// /// [Optional] Authentication context needed to fetch the event or related object. /// [JsonProperty("context")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("context")] -#endif public StripeContext? Context { get; internal set; } protected StripeClient? Client { get; set; } @@ -115,6 +99,7 @@ protected async Task FetchEventAsync(CancellationToken cancellationToken = { Usage = new List { "fetch_event" }, StripeContext = this.Context, + StripeRequestTrigger = $"event={this.Id}", }, cancellationToken: cancellationToken).ConfigureAwait(false); } @@ -140,6 +125,7 @@ protected virtual async Task FetchRelatedObjectAsync(EventNotificationRela { Usage = new List { "fetch_related_object" }, StripeContext = this.Context, + StripeRequestTrigger = $"event={this.Id}", }, cancellationToken: cancellationToken) .ConfigureAwait(false); diff --git a/src/Stripe.net/Entities/V2/Core/EventNotificationReason.cs b/src/Stripe.net/Entities/V2/Core/EventNotificationReason.cs index 41fa17e472..b516dcc395 100644 --- a/src/Stripe.net/Entities/V2/Core/EventNotificationReason.cs +++ b/src/Stripe.net/Entities/V2/Core/EventNotificationReason.cs @@ -1,9 +1,7 @@ namespace Stripe.V2.Core { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif /// /// The non-StripeEntity version of a Reason. @@ -14,18 +12,14 @@ public class EventNotificationReason /// Event reason type. /// [JsonProperty("type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("type")] -#endif public string Type { get; set; } /// /// Information on the API request that instigated the event. /// [JsonProperty("request")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("request")] -#endif public EventNotificationReasonRequest Request { get; set; } } } \ No newline at end of file diff --git a/src/Stripe.net/Entities/V2/Core/EventNotificationReasonRequest.cs b/src/Stripe.net/Entities/V2/Core/EventNotificationReasonRequest.cs index b9b193ff05..7dd041264a 100644 --- a/src/Stripe.net/Entities/V2/Core/EventNotificationReasonRequest.cs +++ b/src/Stripe.net/Entities/V2/Core/EventNotificationReasonRequest.cs @@ -1,9 +1,7 @@ namespace Stripe.V2.Core { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif /// /// The non-StripeEntity version of a ReasonRequest. @@ -14,18 +12,14 @@ public class EventNotificationReasonRequest /// ID of the API request that caused the event. /// [JsonProperty("id")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("id")] -#endif public string Id { get; set; } /// /// The idempotency key transmitted during the request. /// [JsonProperty("idempotency_key")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("idempotency_key")] -#endif public string IdempotencyKey { get; set; } } } \ No newline at end of file diff --git a/src/Stripe.net/Entities/V2/Core/EventNotificationRelatedObject.cs b/src/Stripe.net/Entities/V2/Core/EventNotificationRelatedObject.cs index 830298a13e..44ad787c7d 100644 --- a/src/Stripe.net/Entities/V2/Core/EventNotificationRelatedObject.cs +++ b/src/Stripe.net/Entities/V2/Core/EventNotificationRelatedObject.cs @@ -3,28 +3,23 @@ namespace Stripe.V2.Core { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class EventNotificationRelatedObject { [JsonProperty("id")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("id")] -#endif + [STJS.JsonInclude] public string Id { get; internal set; } [JsonProperty("type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("type")] -#endif + [STJS.JsonInclude] public string Type { get; internal set; } [JsonProperty("url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("url")] -#endif + [STJS.JsonInclude] public string Url { get; internal set; } } } \ No newline at end of file diff --git a/src/Stripe.net/Entities/V2/Core/Events/Event.partial.cs b/src/Stripe.net/Entities/V2/Core/Events/Event.partial.cs index 5ac01c61d1..76c2f1fed1 100644 --- a/src/Stripe.net/Entities/V2/Core/Events/Event.partial.cs +++ b/src/Stripe.net/Entities/V2/Core/Events/Event.partial.cs @@ -5,28 +5,21 @@ namespace Stripe.V2.Core using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; /// /// Manually-maintained convenience methods added to V2 Events. /// [JsonConverter(typeof(V2EventConverter))] -#if NET6_0_OR_GREATER [STJS.JsonConverter(typeof(STJV2EventConverter))] -#endif public partial class Event : StripeEntity, IHasId, IHasObject { /// /// Used for .FetchObject and .FetchData helpers. /// [JsonIgnore] -#if NET6_0_OR_GREATER [STJS.JsonIgnore] -#endif internal ApiRequestor Requestor { get; set; } @@ -63,10 +56,13 @@ protected virtual Task FetchRelatedObjectAsync(EventRelatedObject relatedO return null; } - RequestOptions opts = null; + RequestOptions opts = new RequestOptions + { + StripeRequestTrigger = $"event={this.Id}", + }; if (this.Context != null) { - opts = new RequestOptions { StripeContext = this.Context }; + opts.StripeContext = this.Context; } return this.Requestor.RequestAsync( diff --git a/src/Stripe.net/Entities/V2/Core/Events/EventRelatedObject.cs b/src/Stripe.net/Entities/V2/Core/Events/EventRelatedObject.cs index d631bf07e5..00f0794038 100644 --- a/src/Stripe.net/Entities/V2/Core/Events/EventRelatedObject.cs +++ b/src/Stripe.net/Entities/V2/Core/Events/EventRelatedObject.cs @@ -1,9 +1,7 @@ namespace Stripe.V2.Core { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class EventRelatedObject : StripeEntity, IHasId { @@ -11,27 +9,21 @@ public class EventRelatedObject : StripeEntity, IHasId /// Unique identifier for the object relevant to the event. /// [JsonProperty("id")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("id")] -#endif public string Id { get; set; } /// /// Type of the object relevant to the event. /// [JsonProperty("type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("type")] -#endif public string Type { get; set; } /// /// URL to retrieve the resource. /// [JsonProperty("url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("url")] -#endif public string Url { get; set; } } } diff --git a/src/Stripe.net/Entities/V2/StripeList.cs b/src/Stripe.net/Entities/V2/StripeList.cs index 2d7549d370..6ec72e0ee0 100644 --- a/src/Stripe.net/Entities/V2/StripeList.cs +++ b/src/Stripe.net/Entities/V2/StripeList.cs @@ -3,15 +3,11 @@ namespace Stripe.V2 using System.Collections; using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER using Stripe.Infrastructure; using STJS = System.Text.Json.Serialization; -#endif [JsonObject] -#if NET6_0_OR_GREATER [STJS.JsonConverter(typeof(STJEnumerableObjectConverter))] -#endif public class StripeList : StripeEntity>, IEnumerable { /// @@ -19,27 +15,21 @@ public class StripeList : StripeEntity>, IEnumerable /// TODO(jar) does this need an ItemConverterType (like in Stripe.StripeList). /// [JsonProperty("data")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("data")] -#endif public List Data { get; set; } /// /// The URL for accessing this list. /// [JsonProperty("next_page_url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("next_page_url")] -#endif public string NextPageUrl { get; set; } /// /// The URL for accessing this list. /// [JsonProperty("previous_page_url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("previous_page_url")] -#endif public string PreviousPageUrl { get; set; } public IEnumerator GetEnumerator() diff --git a/src/Stripe.net/Entities/_base/StripeEntity.cs b/src/Stripe.net/Entities/_base/StripeEntity.cs index 9a14beaed0..b48ba5f301 100644 --- a/src/Stripe.net/Entities/_base/StripeEntity.cs +++ b/src/Stripe.net/Entities/_base/StripeEntity.cs @@ -1,24 +1,27 @@ namespace Stripe { + using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; + using System.Text.Json; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Stripe.Infrastructure; - -#if NET6_0_OR_GREATER using STJ = System.Text.Json; using STJS = System.Text.Json.Serialization; -#endif [JsonObject(MemberSerialization.OptIn)] [JsonConverter(typeof(StripeEntityConverter))] - [NoSystemTextJsonAttributesNeeded("Converter is only needed for deserialization in Stripe.net. Member serialization opt-in is implemented in STJMemberSerializationOptIn, which is placed on the concrete classes")] + [STJS.JsonConverter(typeof(STJStripeEntityConverter))] public abstract class StripeEntity : IStripeEntity { + private string rawJsonString; + private JObject rawJObject; + private STJ.JsonElement? rawJsonElement; + /// /// Gets the raw JObject exposed by the Newtonsoft.Json library. /// This can be used to access properties that are not directly exposed by Stripe's .NET @@ -33,15 +36,63 @@ public abstract class StripeEntity : IStripeEntity /// /// The raw JObject. [JsonIgnore] -#if NET6_0_OR_GREATER [STJS.JsonIgnore] -#endif - public JObject RawJObject { get; protected set; } + [Obsolete("Use RawJsonElement instead. RawJObject will be removed in a future major version.")] +#pragma warning disable CS0618 // Type or member is obsolete + public JObject RawJObject + { + get + { + if (this.rawJObject == null && this.rawJsonString != null) + { + this.rawJObject = JObject.Parse(this.rawJsonString); + } + + return this.rawJObject; + } + + protected set + { + this.rawJObject = value; + + // Clear the raw string if someone sets the JObject directly + this.rawJsonString = null; + } + } +#pragma warning restore CS0618 // Type or member is obsolete + + /// + /// Gets the raw JSON returned by Stripe's API as a . + /// The is lazily parsed from the stored raw JSON + /// string on first access to avoid pinning a + /// buffer in memory for every entity. + /// + [JsonIgnore] + [STJS.JsonIgnore] + public STJ.JsonElement? RawJsonElement + { + get + { + if (this.rawJsonElement == null && this.rawJsonString != null) + { + // Parse on demand. The returned JsonElement is backed by a + // JsonDocument that is never disposed — this is intentional, + // as the element escapes the scope and the caller may hold + // a reference to it indefinitely. + this.rawJsonElement = STJ.JsonDocument.Parse(this.rawJsonString).RootElement; + } + + return this.rawJsonElement; + } + + protected set + { + this.rawJsonElement = value; + } + } [JsonIgnore] -#if NET6_0_OR_GREATER [STJS.JsonIgnore] -#endif public StripeResponse StripeResponse { get; set; } /// @@ -52,7 +103,8 @@ public abstract class StripeEntity : IStripeEntity /// The deserialized Stripe object from the JSON string. public static IHasObject FromJson(string value) { - return JsonUtils.DeserializeObject(value, StripeConfiguration.SerializerSettings); + return STJ.JsonSerializer.Deserialize( + value, StripeConfiguration.SerializerOptions); } /// Deserializes the JSON to the specified Stripe object type. @@ -62,7 +114,8 @@ public static IHasObject FromJson(string value) public static T FromJson(string value) where T : IStripeEntity { - return JsonUtils.DeserializeObject(value, StripeConfiguration.SerializerSettings); + return STJ.JsonSerializer.Deserialize( + value, StripeConfiguration.SerializerOptions); } /// Deserializes the JSON to the specified Stripe object type. @@ -76,15 +129,24 @@ internal static T FromJson(string value, JsonSerializerSettings settings) return JsonUtils.DeserializeObject(value, settings); } - internal static T FromJson(JToken value) + internal static T FromJson(JsonElement value) where T : IStripeEntity { - return JsonUtils.DeserializeObject(value, StripeConfiguration.SerializerSettings); + // return JsonUtils.DeserializeObject(value, StripeConfiguration.SerializerSettings); + return STJ.JsonSerializer.Deserialize( + value, StripeConfiguration.SerializerOptions); } internal void SetRawJObject(JObject rawJObject) { +#pragma warning disable CS0618 // Type or member is obsolete this.RawJObject = rawJObject; +#pragma warning restore CS0618 // Type or member is obsolete + } + + internal void SetRawJsonString(string rawJson) + { + this.rawJsonString = rawJson; } /// Reports a Stripe object as a string. @@ -110,10 +172,10 @@ public override string ToString() /// An indented JSON string represensation of the object. public string ToJson() { - return JsonUtils.SerializeObject( + return STJ.JsonSerializer.Serialize( this, - Formatting.Indented, - StripeConfiguration.SerializerSettings); + this.GetType(), + StripeConfiguration.IndentedSerializerOptions); } /// @@ -218,5 +280,10 @@ public abstract class StripeEntity : StripeEntity { return StripeEntity.FromJson(value); } + + internal static T FromJson(JsonElement value) + { + return StripeEntity.FromJson(value); + } } } diff --git a/src/Stripe.net/Entities/_common/Address.cs b/src/Stripe.net/Entities/_common/Address.cs index b0ec7e2b81..15b0cdff41 100644 --- a/src/Stripe.net/Entities/_common/Address.cs +++ b/src/Stripe.net/Entities/_common/Address.cs @@ -1,46 +1,32 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class Address : StripeEntity
{ [JsonProperty("city")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("city")] -#endif public string City { get; set; } [JsonProperty("country")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("country")] -#endif public string Country { get; set; } [JsonProperty("line1")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("line1")] -#endif public string Line1 { get; set; } [JsonProperty("line2")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("line2")] -#endif public string Line2 { get; set; } [JsonProperty("postal_code")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("postal_code")] -#endif public string PostalCode { get; set; } [JsonProperty("state")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("state")] -#endif public string State { get; set; } } } diff --git a/src/Stripe.net/Entities/_common/AddressJapan.cs b/src/Stripe.net/Entities/_common/AddressJapan.cs index d1515cb7e2..65f762d539 100644 --- a/src/Stripe.net/Entities/_common/AddressJapan.cs +++ b/src/Stripe.net/Entities/_common/AddressJapan.cs @@ -1,16 +1,12 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class AddressJapan : Address { [JsonProperty("town")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("town")] -#endif public string Town { get; set; } } } diff --git a/src/Stripe.net/Entities/_common/Amount.cs b/src/Stripe.net/Entities/_common/Amount.cs index 4641e86415..98cf303543 100644 --- a/src/Stripe.net/Entities/_common/Amount.cs +++ b/src/Stripe.net/Entities/_common/Amount.cs @@ -1,22 +1,16 @@ namespace Stripe.V2 { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class Amount { [JsonProperty("value")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("value")] -#endif public long Value { get; set; } [JsonProperty("currency")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("currency")] -#endif public string Currency { get; set; } } } diff --git a/src/Stripe.net/Entities/_common/Shipping.cs b/src/Stripe.net/Entities/_common/Shipping.cs index 7bd15d42f6..c639b96b4d 100644 --- a/src/Stripe.net/Entities/_common/Shipping.cs +++ b/src/Stripe.net/Entities/_common/Shipping.cs @@ -1,40 +1,28 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class Shipping : StripeEntity { [JsonProperty("address")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("address")] -#endif public Address Address { get; set; } [JsonProperty("carrier")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("carrier")] -#endif public string Carrier { get; set; } [JsonProperty("name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("name")] -#endif public string Name { get; set; } [JsonProperty("phone")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("phone")] -#endif public string Phone { get; set; } [JsonProperty("tracking_number")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("tracking_number")] -#endif public string TrackingNumber { get; set; } } } diff --git a/src/Stripe.net/Entities/_interfaces/IBalanceTransactionSource.cs b/src/Stripe.net/Entities/_interfaces/IBalanceTransactionSource.cs index c3b4a5772b..11c9430593 100644 --- a/src/Stripe.net/Entities/_interfaces/IBalanceTransactionSource.cs +++ b/src/Stripe.net/Entities/_interfaces/IBalanceTransactionSource.cs @@ -1,9 +1,7 @@ namespace Stripe { -#if NET6_0_OR_GREATER using Stripe.Infrastructure; using STJS = System.Text.Json.Serialization; -#endif /// /// Resources that implement this interface can appear as sources in balance transactions. @@ -44,9 +42,7 @@ namespace Stripe /// /// /// -#if NET6_0_OR_GREATER [STJS.JsonConverter(typeof(STJStripeObjectConverter))] -#endif public interface IBalanceTransactionSource : IStripeEntity, IHasId, IHasObject { } diff --git a/src/Stripe.net/Entities/_interfaces/IExternalAccount.cs b/src/Stripe.net/Entities/_interfaces/IExternalAccount.cs index d7c3f84ef5..868b7f21af 100644 --- a/src/Stripe.net/Entities/_interfaces/IExternalAccount.cs +++ b/src/Stripe.net/Entities/_interfaces/IExternalAccount.cs @@ -1,9 +1,7 @@ namespace Stripe { -#if NET6_0_OR_GREATER using Stripe.Infrastructure; using STJS = System.Text.Json.Serialization; -#endif /// /// Resources that implement this interface can be used as external accounts, i.e. they can @@ -18,9 +16,7 @@ namespace Stripe /// /// /// -#if NET6_0_OR_GREATER [STJS.JsonConverter(typeof(STJStripeObjectConverter))] -#endif public interface IExternalAccount : IStripeEntity, IHasId, IHasObject { Account Account { get; } diff --git a/src/Stripe.net/Entities/_interfaces/IHasObject.cs b/src/Stripe.net/Entities/_interfaces/IHasObject.cs index b9238c60ae..5c55d8635b 100644 --- a/src/Stripe.net/Entities/_interfaces/IHasObject.cs +++ b/src/Stripe.net/Entities/_interfaces/IHasObject.cs @@ -1,16 +1,12 @@ namespace Stripe { -#if NET6_0_OR_GREATER using Stripe.Infrastructure; using STJS = System.Text.Json.Serialization; -#endif /// /// Interface that identifies entities returned by Stripe that have an `object` attribute. /// -#if NET6_0_OR_GREATER [STJS.JsonConverter(typeof(STJStripeObjectConverter))] -#endif public interface IHasObject { /// diff --git a/src/Stripe.net/Entities/_interfaces/IPaymentSource.cs b/src/Stripe.net/Entities/_interfaces/IPaymentSource.cs index d19362a24e..9254c3c6a4 100644 --- a/src/Stripe.net/Entities/_interfaces/IPaymentSource.cs +++ b/src/Stripe.net/Entities/_interfaces/IPaymentSource.cs @@ -1,9 +1,7 @@ namespace Stripe { -#if NET6_0_OR_GREATER using Stripe.Infrastructure; using STJS = System.Text.Json.Serialization; -#endif /// /// Resources that implement this interface can be used as payment sources when creating @@ -24,9 +22,7 @@ namespace Stripe /// /// /// -#if NET6_0_OR_GREATER [STJS.JsonConverter(typeof(STJStripeObjectConverter))] -#endif public interface IPaymentSource : IStripeEntity, IHasId, IHasObject { } diff --git a/src/Stripe.net/Events/UnknownEventNotification.cs b/src/Stripe.net/Events/UnknownEventNotification.cs index 325362662e..8a62979b19 100644 --- a/src/Stripe.net/Events/UnknownEventNotification.cs +++ b/src/Stripe.net/Events/UnknownEventNotification.cs @@ -6,9 +6,7 @@ namespace Stripe.Events using System.Threading.Tasks; using Newtonsoft.Json; using Stripe.V2.Core; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif /// /// Represents an EventNotification that is valid, but that the SDK doesn't have types for. May have a RelatedObject and can be used to fetch the corresponding full event. @@ -20,9 +18,7 @@ public class UnknownEventNotification : V2.Core.EventNotification /// [Optional] Object containing the reference to API resource relevant to the event. /// [JsonProperty("related_object")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("related_object")] -#endif public EventNotificationRelatedObject? RelatedObject { get; internal set; } public V2.Core.Event FetchEvent() diff --git a/src/Stripe.net/Infrastructure/FormEncoding/ContentEncoder.cs b/src/Stripe.net/Infrastructure/FormEncoding/ContentEncoder.cs index b90011e0dd..e425fbaca3 100644 --- a/src/Stripe.net/Infrastructure/FormEncoding/ContentEncoder.cs +++ b/src/Stripe.net/Infrastructure/FormEncoding/ContentEncoder.cs @@ -9,7 +9,8 @@ namespace Stripe.Infrastructure.FormEncoding using System.Net; using System.Net.Http; using System.Reflection; - using Newtonsoft.Json; + using System.Runtime.Serialization; + using STJS = System.Text.Json.Serialization; internal enum ArrayEncoding { @@ -166,7 +167,10 @@ private static List> FlattenParamsValue(object valu break; case Enum e: - flatParams = SingleParam(keyPrefix, JsonUtils.SerializeObject(e).Trim('"')); + var enumMember = e.GetType().GetField(e.ToString()) + ?.GetCustomAttribute(); + var enumValue = enumMember?.Value ?? e.ToString(); + flatParams = SingleParam(keyPrefix, enumValue); break; case bool b: @@ -236,20 +240,33 @@ private static List> FlattenParamsOptions( foreach (var property in options.GetType().GetRuntimeProperties()) { - // `[JsonExtensionData]` tells the serializer to write the values contained in - // the collection as if they were class properties. - var extensionAttribute = property.GetCustomAttribute(); - if (extensionAttribute != null) + // Check STJ [JsonExtensionData] first, fall back to Newtonsoft + var stjExtension = property.GetCustomAttribute(); + var nsjExtension = property.GetCustomAttribute(); + if (stjExtension != null || nsjExtension != null) { var extensionValue = property.GetValue(options, null) as IDictionary; - flatParams.AddRange(FlattenParamsDictionary(extensionValue, keyPrefix, arrayEncoding)); continue; } - // Skip properties not annotated with `[JsonProperty]` - var attribute = property.GetCustomAttribute(); - if (attribute == null) + // Check STJ [JsonPropertyName] first, fall back to Newtonsoft [JsonProperty] + string key = null; + var stjAttribute = property.GetCustomAttribute(); + if (stjAttribute != null) + { + key = stjAttribute.Name; + } + else + { + var nsjAttribute = property.GetCustomAttribute(); + if (nsjAttribute != null) + { + key = nsjAttribute.PropertyName; + } + } + + if (key == null) { continue; } @@ -263,7 +280,6 @@ private static List> FlattenParamsOptions( continue; } - string key = attribute.PropertyName; string newPrefix = NewPrefix(key, keyPrefix); flatParams.AddRange(FlattenParamsValue(value, newPrefix, arrayEncoding)); diff --git a/src/Stripe.net/Infrastructure/FormEncoding/JsonEncodedContent.cs b/src/Stripe.net/Infrastructure/FormEncoding/JsonEncodedContent.cs index efaeff82e4..c73b7f6438 100644 --- a/src/Stripe.net/Infrastructure/FormEncoding/JsonEncodedContent.cs +++ b/src/Stripe.net/Infrastructure/FormEncoding/JsonEncodedContent.cs @@ -3,8 +3,8 @@ namespace Stripe.Infrastructure.FormEncoding using System; using System.Net.Http; using System.Net.Http.Headers; - using System.Text; - using Newtonsoft.Json; + using System.Text.Json; + using STJS = System.Text.Json.Serialization; /// /// A container for name/value tuples encoded using application/json @@ -12,7 +12,7 @@ namespace Stripe.Infrastructure.FormEncoding /// internal class JsonEncodedContent : ByteArrayContent { - private static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }; + private static readonly JsonSerializerOptions SerializerOptions = CreateOptions(); /// /// Initializes a new instance of the class. @@ -25,6 +25,13 @@ public JsonEncodedContent(BaseOptions options) this.Headers.ContentType.CharSet = "utf-8"; } + private static JsonSerializerOptions CreateOptions() + { + var opts = StripeConfiguration.DefaultStjSerializerOptions(); + opts.DefaultIgnoreCondition = STJS.JsonIgnoreCondition.WhenWritingNull; + return opts; + } + private static byte[] CreateContentByteArray( BaseOptions options) { @@ -33,7 +40,7 @@ private static byte[] CreateContentByteArray( throw new ArgumentNullException(nameof(options)); } - return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(options, Formatting.None, SerializerSettings)); + return JsonSerializer.SerializeToUtf8Bytes(options, options.GetType(), SerializerOptions); } } } \ No newline at end of file diff --git a/src/Stripe.net/Infrastructure/JsonConverters/DecimalStringConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/DecimalStringConverter.cs new file mode 100644 index 0000000000..768c861671 --- /dev/null +++ b/src/Stripe.net/Infrastructure/JsonConverters/DecimalStringConverter.cs @@ -0,0 +1,37 @@ +namespace Stripe.Infrastructure +{ + using System; + using System.Globalization; + using Newtonsoft.Json; + + /// + /// A Newtonsoft.Json converter for decimal fields that are transmitted as + /// strings in the Stripe API (the decimal_string format). This + /// ensures parity with the STJ [JsonNumberHandling(AllowReadingFromString + /// | WriteAsString)] attribute applied to the same fields. + /// + internal class DecimalStringConverter : JsonConverter + { + public override decimal ReadJson(JsonReader reader, Type objectType, decimal existingValue, bool hasExistingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + { + return 0m; + } + + if (reader.TokenType == JsonToken.String) + { + var str = (string)reader.Value; + return decimal.Parse(str, CultureInfo.InvariantCulture); + } + + // Also accept bare numbers for flexibility + return Convert.ToDecimal(reader.Value, CultureInfo.InvariantCulture); + } + + public override void WriteJson(JsonWriter writer, decimal value, JsonSerializer serializer) + { + writer.WriteValue(value.ToString(CultureInfo.InvariantCulture)); + } + } +} diff --git a/src/Stripe.net/Infrastructure/JsonConverters/Int64StringConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/Int64StringConverter.cs new file mode 100644 index 0000000000..f3e00b8d94 --- /dev/null +++ b/src/Stripe.net/Infrastructure/JsonConverters/Int64StringConverter.cs @@ -0,0 +1,78 @@ +namespace Stripe.Infrastructure +{ + using System; + using Newtonsoft.Json; + + /// + /// A Newtonsoft.Json converter for long fields that are transmitted as + /// strings in the Stripe API (the int64_string format). This + /// ensures parity with the STJ [JsonNumberHandling(AllowReadingFromString + /// | WriteAsString)] attribute applied to the same fields. + /// + internal class Int64StringConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(long) || objectType == typeof(long?); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value == null) + { + writer.WriteNull(); + return; + } + + writer.WriteValue(value.ToString()); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + bool nullable = IsNullable(objectType); + if (reader.TokenType == JsonToken.Null) + { + if (!nullable) + { + throw new JsonSerializationException(string.Format("Cannot convert null value to {0}.", objectType)); + } + + return null; + } + + long value; + if (reader.TokenType == JsonToken.String) + { + if (!long.TryParse((string)reader.Value!, out value)) + { + throw new JsonSerializationException(string.Format("Cannot convert invalid value to {0}.", objectType)); + } + } + else if (reader.TokenType == JsonToken.Integer) + { + value = (long)reader.Value!; + } + else + { + throw new JsonSerializationException(string.Format("Unexpected token parsing integer. Expected String or Integer, got {0}.", reader.TokenType)); + } + + return value; + } + + private static bool IsNullable(Type t) + { + if (t == null) + { + throw new ArgumentNullException(nameof(t)); + } + + if (t.IsValueType) + { + return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>); + } + + return true; + } + } +} diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJAnyOfConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJAnyOfConverter.cs index 356ebc65cc..2b20015bc0 100644 --- a/src/Stripe.net/Infrastructure/JsonConverters/STJAnyOfConverter.cs +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJAnyOfConverter.cs @@ -1,4 +1,3 @@ -#if NET6_0_OR_GREATER namespace Stripe.Infrastructure { using System; @@ -93,4 +92,3 @@ public override bool CanConvert(Type objectType) } } } -#endif diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJDefaultConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJDefaultConverter.cs index 0eda9da43b..eba571bb8b 100644 --- a/src/Stripe.net/Infrastructure/JsonConverters/STJDefaultConverter.cs +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJDefaultConverter.cs @@ -1,7 +1,9 @@ -#if NET6_0_OR_GREATER namespace Stripe.Infrastructure { using System; + using System.Collections; + using System.Collections.Generic; + using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using static Stripe.Infrastructure.SerializablePropertyCache; @@ -30,8 +32,21 @@ protected T ReadFullObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSe } var allProperties = GetPropertiesForType(typeToConvert); + var extensionDataInfo = GetExtensionDataPropertyForType(typeToConvert); var newInstance = Activator.CreateInstance(typeToConvert); + // If there's an extension data property, get or create the dictionary + IDictionary extensionData = null; + if (extensionDataInfo != null) + { + extensionData = extensionDataInfo.Get(newInstance) as IDictionary; + if (extensionData == null) + { + extensionData = new Dictionary(); + extensionDataInfo.Set(newInstance, extensionData); + } + } + while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) @@ -54,14 +69,53 @@ protected T ReadFullObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSe if (property != null) { var valueType = property.PropertyInfo.PropertyType; - var valueConverter = property.GetConverter(options); - // Get the value. + // Check for a custom converter attribute on the property + if (property.CustomConverterType != null) + { + var valueConverter = property.GetConverter(options); + + // Get the value using the custom converter. #pragma warning disable SA1009 // Closing parenthesis should be spaced correctly - object value = valueConverter.Read(ref reader, valueType, options)!; + object value = valueConverter.Read(ref reader, valueType, options)!; #pragma warning restore SA1009 // Closing parenthesis should be spaced correctly - property.Set(newInstance, value); + property.Set(newInstance, value); + } + else if (property.NumberHandling.HasValue && + (property.NumberHandling.Value & JsonNumberHandling.AllowReadingFromString) != 0 && + reader.TokenType == JsonTokenType.String) + { + // Property has [JsonNumberHandling(AllowReadingFromString)] and + // the wire value is a JSON string — parse the number from the string. + var str = reader.GetString(); + if (str == null) + { + property.Set(newInstance, null); + } + else + { + // Unwrap Nullable to get the underlying type for Convert.ChangeType + var targetType = Nullable.GetUnderlyingType(valueType) ?? valueType; + property.Set(newInstance, Convert.ChangeType(str, targetType, CultureInfo.InvariantCulture)); + } + } + else + { + object value = JsonSerializer.Deserialize(ref reader, valueType, options); + property.Set(newInstance, value); + } + } + else if (extensionData != null) + { + // Store unknown properties in the extension data dictionary + var element = JsonSerializer.Deserialize(ref reader, options); + extensionData[propertyName] = element; + } + else + { + // Skip unknown properties to keep the reader aligned + reader.Skip(); } } @@ -76,7 +130,9 @@ protected T ReadFullObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSe /// The calling serializer's options. public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { - var allProperties = GetPropertiesForType(value.GetType()); + var type = value.GetType(); + var allProperties = GetPropertiesForType(type); + var extensionDataInfo = GetExtensionDataPropertyForType(type); writer.WriteStartObject(); foreach (var property in allProperties) @@ -86,7 +142,11 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions switch (valueToSerialize) { case null: - if (property.IgnoreCondition != JsonIgnoreCondition.WhenWritingNull) + // Use property-level ignore condition if set, otherwise use global setting + var effectiveIgnoreCondition = property.IgnoreCondition ?? options.DefaultIgnoreCondition; + + if (effectiveIgnoreCondition != JsonIgnoreCondition.WhenWritingNull && + effectiveIgnoreCondition != JsonIgnoreCondition.Always) { writer.WritePropertyName(property.JsonPropertyName); writer.WriteNullValue(); @@ -96,15 +156,42 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions default: writer.WritePropertyName(property.JsonPropertyName); - var converter = property.GetConverter(options); - converter.Write(writer, valueToSerialize, options); + if (property.NumberHandling.HasValue && + (property.NumberHandling.Value & JsonNumberHandling.WriteAsString) != 0 && + valueToSerialize is IConvertible) + { + writer.WriteStringValue(Convert.ToString(valueToSerialize, CultureInfo.InvariantCulture)); + } + else + { + var converter = property.GetConverter(options); + converter.Write(writer, valueToSerialize, options); + } break; } } + // Write extension data entries (e.g. ExtraParams) as top-level properties + if (extensionDataInfo != null) + { + if (extensionDataInfo.Get(value) is IDictionary extData) + { + foreach (DictionaryEntry entry in extData) + { + var key = entry.Key?.ToString(); + if (key == null) + { + continue; + } + + writer.WritePropertyName(key); + JsonSerializer.Serialize(writer, entry.Value, options); + } + } + } + writer.WriteEndObject(); } } } -#endif diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJEmptyableConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJEmptyableConverter.cs index bba884dfff..de7fb871f0 100644 --- a/src/Stripe.net/Infrastructure/JsonConverters/STJEmptyableConverter.cs +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJEmptyableConverter.cs @@ -1,4 +1,3 @@ -#if NET6_0_OR_GREATER namespace Stripe.Infrastructure { using System; @@ -74,4 +73,3 @@ public override Emptyable Read(ref Utf8JsonReader reader, Type typeToConvert, } } } -#endif diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJEnumerableObjectConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJEnumerableObjectConverter.cs index 66cdc304a8..ce8914d4c3 100644 --- a/src/Stripe.net/Infrastructure/JsonConverters/STJEnumerableObjectConverter.cs +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJEnumerableObjectConverter.cs @@ -1,4 +1,3 @@ -#if NET6_0_OR_GREATER namespace Stripe.Infrastructure { using System; @@ -47,20 +46,8 @@ public override JsonConverter CreateConverter( return converter; } - internal class STJEnumerableObjectConverterInner : JsonConverter + internal class STJEnumerableObjectConverterInner : STJDefaultConverter { - /// - /// Reads the JSON representation of the object. - /// - /// The to read from. - /// Type of the object. - /// The calling serializer's options. - /// The object value. - public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - throw new NotSupportedException("STJEnumerableObjectConverter should only be used while serializing."); - } - /// /// Writes the JSON representation of the object. /// @@ -96,4 +83,3 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions } } } -#endif diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJEventConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJEventConverter.cs new file mode 100644 index 0000000000..a9ce2b15b5 --- /dev/null +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJEventConverter.cs @@ -0,0 +1,67 @@ +namespace Stripe.Infrastructure +{ + using System; + using System.Text; + using System.Text.Json; + using System.Text.Json.Nodes; + using System.Text.Json.Serialization; + + /// + /// STJ converter for Event objects. Handles legacy API version patching + /// (converting string `request` field to object format for API versions + /// before 2017-05-25). + /// + /// This converter extends and uses + /// directly, avoiding + /// pipeline re-entry and the need for self-removal recursion. + /// + internal class STJEventConverter : STJDefaultConverter + { + public override Event Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + // Parse into a mutable JsonNode for potential patching + var jsonNode = JsonNode.Parse(ref reader); + + // Handle breaking change in API version 2017-05-25: + // If `request` is a string, convert it to an object + var requestNode = jsonNode["request"]; + if (requestNode != null && requestNode is JsonValue) + { + var requestId = requestNode.GetValue(); + if (requestId != null) + { + var requestObject = new JsonObject + { + ["id"] = requestId, + ["idempotency_key"] = null, + }; + jsonNode["request"] = requestObject; + } + } + + // Deserialize the (possibly patched) JSON via ReadFullObject + var patchedJson = jsonNode.ToJsonString(); + var bytes = Encoding.UTF8.GetBytes(patchedJson); + var newReader = new Utf8JsonReader(bytes, new JsonReaderOptions + { + AllowTrailingCommas = options.AllowTrailingCommas, + CommentHandling = options.ReadCommentHandling, + MaxDepth = options.MaxDepth, + }); + newReader.Read(); + + var entity = this.ReadFullObject(ref newReader, typeToConvert, options); + + // Store raw JSON so RawJObject and RawJsonElement are available, + // matching the behavior of STJStripeEntityConverter. + entity.SetRawJsonString(patchedJson); + + return entity; + } + } +} diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJEventDataConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJEventDataConverter.cs new file mode 100644 index 0000000000..dc538f3389 --- /dev/null +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJEventDataConverter.cs @@ -0,0 +1,67 @@ +namespace Stripe.Infrastructure +{ + using System; + using System.Text; + using System.Text.Json; + using System.Text.Json.Serialization; + + /// + /// STJ converter for EventData objects. Captures raw JSON strings for + /// data.object and data.previous_attributes so they can + /// be lazily accessed via and + /// . + /// + internal class STJEventDataConverter : STJDefaultConverter + { + public override EventData Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + // Buffer the entire EventData JSON so we can extract raw strings + // before deserializing properties. + var element = JsonElement.ParseValue(ref reader); + + // Extract raw JSON strings for lazy parsing + string rawObject = null; + string rawPreviousAttributes = null; + + if (element.TryGetProperty("object", out var objProp)) + { + rawObject = objProp.GetRawText(); + } + + if (element.TryGetProperty("previous_attributes", out var prevProp)) + { + rawPreviousAttributes = prevProp.GetRawText(); + } + + // Deserialize via ReadFullObject (no pipeline re-entry) + var bytes = Encoding.UTF8.GetBytes(element.GetRawText()); + var newReader = new Utf8JsonReader(bytes, new JsonReaderOptions + { + AllowTrailingCommas = options.AllowTrailingCommas, + CommentHandling = options.ReadCommentHandling, + MaxDepth = options.MaxDepth, + }); + newReader.Read(); + + var data = this.ReadFullObject(ref newReader, typeToConvert, options); + + // Set raw JSON strings for lazy parsing by EventData properties + if (rawObject != null) + { + data.SetRawObjectJson(rawObject); + } + + if (rawPreviousAttributes != null) + { + data.SetPreviousAttributesJson(rawPreviousAttributes); + } + + return data; + } + } +} diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJExpandableFieldConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJExpandableFieldConverter.cs index 4ff5e851ed..c20f5d8d2d 100644 --- a/src/Stripe.net/Infrastructure/JsonConverters/STJExpandableFieldConverter.cs +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJExpandableFieldConverter.cs @@ -1,4 +1,3 @@ -#if NET6_0_OR_GREATER namespace Stripe.Infrastructure { using System; @@ -134,4 +133,3 @@ public override bool CanConvert(Type typeToConvert) } } } -#endif diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJMemberSerializationOptIn.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJMemberSerializationOptIn.cs deleted file mode 100644 index 476712a107..0000000000 --- a/src/Stripe.net/Infrastructure/JsonConverters/STJMemberSerializationOptIn.cs +++ /dev/null @@ -1,48 +0,0 @@ -#if NET6_0_OR_GREATER -namespace Stripe.Infrastructure -{ - using System; - using System.Reflection; - using System.Text.Json; - using System.Text.Json.Serialization; - using static Stripe.Infrastructure.SerializablePropertyCache; - - /// - /// A JsonConverterFactory to implement the equivalent to - /// Newtonsoft Json.NET [JsonObject(MemberSerialization.OptIn)]. - /// This is needed to serialize non-public properties such as the - /// inner ExpandableField properties. - /// - internal class STJMemberSerializationOptIn : JsonConverterFactory - { - /// - /// Determines whether this instance can convert the specified object type. - /// - /// Type of the object. - /// - /// true if this instance can convert the specified object type; otherwise, false. - /// - public override bool CanConvert(Type objectType) - { - return objectType.IsClass; - } - - public override JsonConverter CreateConverter( - Type type, - JsonSerializerOptions options) - { -#pragma warning disable SA1009 // Closing parenthesis should be spaced correctly - JsonConverter converter = (JsonConverter)Activator.CreateInstance( - typeof(STJDefaultConverter<>).MakeGenericType( - type), - BindingFlags.Instance | BindingFlags.Public, - binder: null, - args: null, - culture: null)!; -#pragma warning restore SA1009 // Closing parenthesis should be spaced correctly - - return converter; - } - } -} -#endif diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJStringInt64Converter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJStringInt64Converter.cs new file mode 100644 index 0000000000..0f763661e8 --- /dev/null +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJStringInt64Converter.cs @@ -0,0 +1,39 @@ +#if NET6_0_OR_GREATER +namespace Stripe.Infrastructure +{ + using System; + using System.Text.Json; + using System.Text.Json.Serialization; + + /// + /// Converts a 64-bit integer to and from a string-encoded JSON integer. + /// + internal class STJStringInt64Converter : JsonConverter + { + public override long Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + if (!long.TryParse(reader.GetString(), out long value)) + { + throw new JsonException(string.Format("Cannot convert invalid value to {0}.", typeToConvert)); + } + + return value; + } + + if (reader.TokenType == JsonTokenType.Number) + { + return reader.GetInt64(); + } + + throw new JsonException(string.Format("Unexpected token parsing integer. Expected String or Number, got {0}.", reader.TokenType)); + } + + public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString()); + } + } +} +#endif diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJStripeEntityConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJStripeEntityConverter.cs new file mode 100644 index 0000000000..d1ea312400 --- /dev/null +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJStripeEntityConverter.cs @@ -0,0 +1,73 @@ +namespace Stripe.Infrastructure +{ + using System; + using System.Reflection; + using System.Text; + using System.Text.Json; + using System.Text.Json.Serialization; + + /// + /// STJ converter factory for StripeEntity types. During deserialization, + /// this converter stores the raw JSON on the entity so that + /// and + /// are populated. + /// + /// Applied as a type-level [JsonConverter] attribute on every + /// generated entity class. Users who create custom entities extending + /// can apply this attribute to get the same + /// serialization behavior. + /// + public class STJStripeEntityConverter : JsonConverterFactory + { + public override bool CanConvert(Type typeToConvert) + { + return typeof(StripeEntity).IsAssignableFrom(typeToConvert); + } + + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + JsonConverter converter = (JsonConverter)Activator.CreateInstance( + typeof(STJStripeEntityConverterInner<>).MakeGenericType(typeToConvert), + BindingFlags.Instance | BindingFlags.Public, + binder: null, + args: null, + culture: null); + return converter; + } + + internal class STJStripeEntityConverterInner : STJDefaultConverter + where T : StripeEntity + { + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + // Consume the reader to extract the raw JSON text. + // JsonElement.ParseValue is the standard STJ way to read + // a complete token from a Utf8JsonReader. We only keep + // the raw text string; the JsonElement (and its backing + // JsonDocument buffer) is discarded immediately. + var rawJson = JsonElement.ParseValue(ref reader).GetRawText(); + + // Deserialize using the base converter's ReadFullObject + var newReader = new Utf8JsonReader(Encoding.UTF8.GetBytes(rawJson), new JsonReaderOptions + { + AllowTrailingCommas = options.AllowTrailingCommas, + CommentHandling = options.ReadCommentHandling, + MaxDepth = options.MaxDepth, + }); + newReader.Read(); // advance to first token + T entity = this.ReadFullObject(ref newReader, typeToConvert, options); + + // Store raw JSON string for lazy RawJObject and RawJsonElement + // properties (both parse on first access). + entity.SetRawJsonString(rawJson); + + return entity; + } + } + } +} diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJStripeObjectConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJStripeObjectConverter.cs index ba76da58c4..12f62f8a7d 100644 --- a/src/Stripe.net/Infrastructure/JsonConverters/STJStripeObjectConverter.cs +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJStripeObjectConverter.cs @@ -1,4 +1,3 @@ -#if NET6_0_OR_GREATER namespace Stripe.Infrastructure { using System; @@ -27,8 +26,11 @@ internal class STJStripeObjectConverter : JsonConverterFactory public override bool CanConvert(Type objectType) { var typeInfo = objectType.GetTypeInfo(); - return (typeInfo.IsInterface && typeInfo.FullName.StartsWith("Stripe")) || - typeInfo.FullName.Equals("Stripe.V2.Core.Event"); + + // Only handle Stripe interfaces for polymorphic dispatch. + // V2.Core.Event is handled by STJV2EventConverter (via class-level attribute) + // which performs dispatch on the "type" property instead of "object". + return typeInfo.IsInterface && typeInfo.FullName.StartsWith("Stripe"); } public override JsonConverter CreateConverter( @@ -68,7 +70,12 @@ public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerial } var jsonObject = JsonElement.ParseValue(ref reader); - var objectValue = jsonObject.GetProperty("object").GetString(); + if (!jsonObject.TryGetProperty("object", out var objectProperty)) + { + return null; + } + + var objectValue = objectProperty.GetString(); Type concreteType = StripeTypeRegistry.GetConcreteType(typeToConvert, objectValue); if (concreteType == null) @@ -82,4 +89,3 @@ public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerial } } } -#endif diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJStripeOptionsConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJStripeOptionsConverter.cs new file mode 100644 index 0000000000..b8d6853804 --- /dev/null +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJStripeOptionsConverter.cs @@ -0,0 +1,36 @@ +namespace Stripe.Infrastructure +{ + using System; + using System.Reflection; + using System.Text.Json; + using System.Text.Json.Serialization; + + /// + /// STJ converter factory for Stripe options types (request parameter + /// classes). Implements opt-in member serialization — only properties + /// annotated with [JsonPropertyName] are included. + /// + /// Applied as a type-level [JsonConverter] attribute on every + /// generated options class. Users who create custom options classes + /// implementing can apply this attribute + /// to get the same serialization behavior. + /// + public class STJStripeOptionsConverter : JsonConverterFactory + { + public override bool CanConvert(Type typeToConvert) + { + return typeof(INestedOptions).IsAssignableFrom(typeToConvert); + } + + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + JsonConverter converter = (JsonConverter)Activator.CreateInstance( + typeof(STJDefaultConverter<>).MakeGenericType(typeToConvert), + BindingFlags.Instance | BindingFlags.Public, + binder: null, + args: null, + culture: null); + return converter; + } + } +} diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJUnixDateTimeConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJUnixDateTimeConverter.cs index 9f6fdcf577..40ba4ad5a8 100644 --- a/src/Stripe.net/Infrastructure/JsonConverters/STJUnixDateTimeConverter.cs +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJUnixDateTimeConverter.cs @@ -1,7 +1,7 @@ -#if NET6_0_OR_GREATER namespace Stripe.Infrastructure { using System; + using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; @@ -13,99 +13,194 @@ namespace Stripe.Infrastructure /// Newtonsoft.Json 11.0. Once we bump the minimum version of Newtonsoft.Json to 11.0, we can /// start using the provided converter and get rid of this class. /// - internal class STJUnixDateTimeConverter : JsonConverter + internal class STJUnixDateTimeConverter : JsonConverterFactory { - /// - /// Reads the JSON representation of the object. - /// - /// The to read from. - /// Type of the object. - /// The calling serializer's options. - /// The object value. - public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override bool CanConvert(Type typeToConvert) { - bool nullable = IsNullable(typeToConvert); - long seconds; + return typeToConvert == typeof(DateTime) || + typeToConvert == typeof(DateTime?); + } - if (reader.TokenType == JsonTokenType.Number) - { - seconds = reader.GetInt64(); - } - else if (reader.TokenType == JsonTokenType.String) + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + if (typeToConvert == typeof(DateTime?)) { - if (!long.TryParse(reader.GetString(), out seconds)) - { - throw new JsonException(string.Format("Cannot convert invalid value to {0}.", typeToConvert)); - } + return (JsonConverter)Activator.CreateInstance( + typeof(NullableDateTimeConverterInner), + BindingFlags.Instance | BindingFlags.Public, + binder: null, + args: null, + culture: null); } else { - throw new JsonException(string.Format("Unexpected token parsing date. Expected Integer or String, got {0}.", reader.TokenType)); + return (JsonConverter)Activator.CreateInstance( + typeof(DateTimeConverterInner), + BindingFlags.Instance | BindingFlags.Public, + binder: null, + args: null, + culture: null); } + } - if (seconds >= 0) + internal class DateTimeConverterInner : JsonConverter + { + /// + /// Reads the JSON representation of the object. + /// + /// The to read from. + /// Type of the object. + /// The calling serializer's options. + /// The object value. + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - // As of the 2025-10-29.clover release, there is a bug in the Terminal API - // where the last_seen_at field is returned as milliseconds rather than seconds. - // Since we don't know when/how a fix will be put in to change that behavior, - // we make a heuristic guess to determine if a timestamp is in milliseconds or seconds. - // This check will work until the year ~5138. - if (seconds > 5000000000L) + long seconds; + + if (reader.TokenType == JsonTokenType.Number) + { + seconds = reader.GetInt64(); + } + else if (reader.TokenType == JsonTokenType.String) { - return DateTimeUtils.UnixEpoch.AddMilliseconds(seconds); + if (!long.TryParse(reader.GetString(), out seconds)) + { + throw new JsonException(string.Format("Cannot convert invalid value to {0}.", typeToConvert)); + } } else { - return DateTimeUtils.UnixEpoch.AddSeconds(seconds); + throw new JsonException(string.Format("Unexpected token parsing date. Expected Integer or String, got {0}.", reader.TokenType)); + } + + if (seconds >= 0) + { + // As of the 2025-10-29.clover release, there is a bug in the Terminal API + // where the last_seen_at field is returned as milliseconds rather than seconds. + // Since we don't know when/how a fix will be put in to change that behavior, + // we make a heuristic guess to determine if a timestamp is in milliseconds or seconds. + // This check will work until the year ~5138. + if (seconds > 5000000000L) + { + return DateTimeUtils.UnixEpoch.AddMilliseconds(seconds); + } + else + { + return DateTimeUtils.UnixEpoch.AddSeconds(seconds); + } + } + else + { + throw new JsonException(string.Format("Cannot convert value that is before Unix epoch of 00:00:00 UTC on 1 January 1970 to {0}.", typeToConvert)); } } - else + + /// + /// Writes the JSON representation of the object. + /// + /// The to write to. + /// The value. + /// The calling serializer's options. + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) { - throw new JsonException(string.Format("Cannot convert value that is before Unix epoch of 00:00:00 UTC on 1 January 1970 to {0}.", typeToConvert)); - } - } + long seconds; - /// - /// Writes the JSON representation of the object. - /// - /// The to write to. - /// The value. - /// The calling serializer's options. - public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) - { - long seconds; + if (value is DateTime dateTime) + { + seconds = (long)(dateTime.ToUniversalTime() - DateTimeUtils.UnixEpoch).TotalSeconds; + } + else + { + throw new JsonException("Expected date object value."); + } - if (value is DateTime dateTime) - { - seconds = (long)(dateTime.ToUniversalTime() - DateTimeUtils.UnixEpoch).TotalSeconds; - } - else - { - throw new JsonException("Expected date object value."); - } + if (seconds < 0) + { + throw new JsonException("Cannot convert date value that is before Unix epoch of 00:00:00 UTC on 1 January 1970."); + } - if (seconds < 0) - { - throw new JsonException("Cannot convert date value that is before Unix epoch of 00:00:00 UTC on 1 January 1970."); + writer.WriteNumberValue(seconds); } - - writer.WriteNumberValue(seconds); } - private static bool IsNullable(Type t) + internal class NullableDateTimeConverterInner : JsonConverter { - if (t == null) + /// + /// Reads the JSON representation of the object. + /// + /// The to read from. + /// Type of the object. + /// The calling serializer's options. + /// The object value. + public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - throw new ArgumentNullException(nameof(t)); + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + long seconds; + + if (reader.TokenType == JsonTokenType.Number) + { + seconds = reader.GetInt64(); + } + else if (reader.TokenType == JsonTokenType.String) + { + if (!long.TryParse(reader.GetString(), out seconds)) + { + throw new JsonException(string.Format("Cannot convert invalid value to {0}.", typeToConvert)); + } + } + else + { + throw new JsonException(string.Format("Unexpected token parsing date. Expected Integer, String, or Null, got {0}.", reader.TokenType)); + } + + if (seconds >= 0) + { + // As of the 2025-10-29.clover release, there is a bug in the Terminal API + // where the last_seen_at field is returned as milliseconds rather than seconds. + // Since we don't know when/how a fix will be put in to change that behavior, + // we make a heuristic guess to determine if a timestamp is in milliseconds or seconds. + // This check will work until the year ~5138. + if (seconds > 5000000000L) + { + return DateTimeUtils.UnixEpoch.AddMilliseconds(seconds); + } + else + { + return DateTimeUtils.UnixEpoch.AddSeconds(seconds); + } + } + else + { + throw new JsonException(string.Format("Cannot convert value that is before Unix epoch of 00:00:00 UTC on 1 January 1970 to {0}.", typeToConvert)); + } } - if (t.IsValueType) + /// + /// Writes the JSON representation of the object. + /// + /// The to write to. + /// The value. + /// The calling serializer's options. + public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) { - return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>); - } + if (value == null) + { + writer.WriteNullValue(); + return; + } - return true; + long seconds = (long)(value.Value.ToUniversalTime() - DateTimeUtils.UnixEpoch).TotalSeconds; + + if (seconds < 0) + { + throw new JsonException("Cannot convert date value that is before Unix epoch of 00:00:00 UTC on 1 January 1970."); + } + + writer.WriteNumberValue(seconds); + } } } } -#endif diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJV2EventConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJV2EventConverter.cs index 7ed335bd96..5bc2dd6ea2 100644 --- a/src/Stripe.net/Infrastructure/JsonConverters/STJV2EventConverter.cs +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJV2EventConverter.cs @@ -1,20 +1,22 @@ -#if NET6_0_OR_GREATER namespace Stripe.Infrastructure { using System; using System.Reflection; + using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using static Stripe.Infrastructure.SerializablePropertyCache; /// - /// Converts a to JSON, including any fields - /// in derived classes. + /// Converts a to and from JSON, including any fields + /// in derived classes. Uses the "type" property for polymorphic dispatch + /// via . /// internal class STJV2EventConverter : STJDefaultConverter { /// - /// Reads the JSON representation of the object. + /// Reads the JSON representation of the object. Uses the "type" property + /// to determine the concrete V2 event class to deserialize into. /// /// The to read from. /// Type of the object. @@ -22,7 +24,49 @@ internal class STJV2EventConverter : STJDefaultConverter /// The object value. public override V2.Core.Event Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - throw new NotSupportedException("STJV2EventConverter should only be used while serializing."); + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + // Buffer the JSON so we can peek at the "type" property + var jsonElement = JsonElement.ParseValue(ref reader); + + // Determine the concrete type from the "type" property + string typeValue = null; + if (jsonElement.TryGetProperty("type", out var typeProp)) + { + typeValue = typeProp.GetString(); + } + + Type concreteType = StripeTypeRegistry.GetConcreteV2EventType(typeValue); + if (concreteType == null) + { + // If "type" is unknown by this SDK, default to the generic Event type. + concreteType = typeof(V2.Core.Event); + } + + // Deserialize using ReadFullObject with the concrete type. + // Get the raw JSON bytes and create a new reader for ReadFullObject. + var rawJson = jsonElement.GetRawText(); + var bytes = Encoding.UTF8.GetBytes(rawJson); + var newReader = new Utf8JsonReader(bytes, new JsonReaderOptions + { + AllowTrailingCommas = options.AllowTrailingCommas, + CommentHandling = options.ReadCommentHandling, + MaxDepth = options.MaxDepth, + }); + + // Advance to the first token (StartObject) + newReader.Read(); + + var entity = this.ReadFullObject(ref newReader, concreteType, options); + + // Store raw JSON so RawJObject and RawJsonElement are available, + // matching the behavior of STJStripeEntityConverter. + entity.SetRawJsonString(rawJson); + + return entity; } /// @@ -38,4 +82,3 @@ public override bool CanConvert(Type objectType) } } } -#endif diff --git a/src/Stripe.net/Infrastructure/JsonConverters/STJV2EventNotificationConverter.cs b/src/Stripe.net/Infrastructure/JsonConverters/STJV2EventNotificationConverter.cs index 2464d304bf..5c1bc08d68 100644 --- a/src/Stripe.net/Infrastructure/JsonConverters/STJV2EventNotificationConverter.cs +++ b/src/Stripe.net/Infrastructure/JsonConverters/STJV2EventNotificationConverter.cs @@ -1,20 +1,22 @@ -#if NET6_0_OR_GREATER namespace Stripe.Infrastructure { using System; using System.Reflection; + using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using static Stripe.Infrastructure.SerializablePropertyCache; /// - /// Converts a to JSON, including any fields - /// in derived classes. + /// Converts a to and from JSON, including any fields + /// in derived classes. Uses the "type" property for polymorphic dispatch + /// via . /// internal class STJV2EventNotificationConverter : STJDefaultConverter { /// - /// Reads the JSON representation of the object. + /// Reads the JSON representation of the object. Uses the "type" property + /// to determine the concrete EventNotification class to deserialize into. /// /// The to read from. /// Type of the object. @@ -22,7 +24,38 @@ internal class STJV2EventNotificationConverter : STJDefaultConverterThe object value. public override V2.Core.EventNotification Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - throw new NotSupportedException("STJV2EventConverter should only be used while serializing."); + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + // Buffer the JSON so we can peek at the "type" property + var jsonElement = JsonElement.ParseValue(ref reader); + + // Determine the concrete type from the "type" property + string typeValue = null; + if (jsonElement.TryGetProperty("type", out var typeProp)) + { + typeValue = typeProp.GetString(); + } + + Type concreteType = StripeTypeRegistry.GetConcreteV2EventNotificationType(typeValue) + ?? typeof(Events.UnknownEventNotification); + + // Deserialize using ReadFullObject with the concrete type. + var rawJson = jsonElement.GetRawText(); + var bytes = Encoding.UTF8.GetBytes(rawJson); + var newReader = new Utf8JsonReader(bytes, new JsonReaderOptions + { + AllowTrailingCommas = options.AllowTrailingCommas, + CommentHandling = options.ReadCommentHandling, + MaxDepth = options.MaxDepth, + }); + + // Advance to the first token (StartObject) + newReader.Read(); + + return this.ReadFullObject(ref newReader, concreteType, options); } /// @@ -38,4 +71,3 @@ public override bool CanConvert(Type objectType) } } } -#endif diff --git a/src/Stripe.net/Infrastructure/JsonConverters/SerializablePropertyCache.cs b/src/Stripe.net/Infrastructure/JsonConverters/SerializablePropertyCache.cs index bacfe7b40c..1061031293 100644 --- a/src/Stripe.net/Infrastructure/JsonConverters/SerializablePropertyCache.cs +++ b/src/Stripe.net/Infrastructure/JsonConverters/SerializablePropertyCache.cs @@ -1,4 +1,3 @@ -#if NET6_0_OR_GREATER namespace Stripe.Infrastructure { using System; @@ -16,6 +15,7 @@ internal class SerializablePropertyCache { private static ConcurrentDictionary converterCache = new ConcurrentDictionary(); private static ConcurrentDictionary> propertyCache = new ConcurrentDictionary>(); + private static ConcurrentDictionary extensionDataCache = new ConcurrentDictionary(); internal static List GetPropertiesForType(Type type) { @@ -27,14 +27,22 @@ internal static List GetPropertiesForType(Type type) var propsToSerialize = new List(); foreach (var prop in rawProps) { + // Skip extension data properties — they're handled separately + if (prop.GetCustomAttribute(typeof(JsonExtensionDataAttribute), false) != null) + { + continue; + } + var propertyNameAttribute = prop.GetCustomAttribute(typeof(JsonPropertyNameAttribute), false) as JsonPropertyNameAttribute; - if (propertyNameAttribute == null) + string jsonPropertyName = propertyNameAttribute?.Name; + + if (jsonPropertyName == null) { - // skip any properties not annotated with JsonPropertyName + // skip any properties not annotated with [JsonPropertyName] continue; } - var ignoreCondition = default(JsonIgnoreCondition); + JsonIgnoreCondition? ignoreCondition = null; if (prop.GetCustomAttribute(typeof(JsonIgnoreAttribute), false) is JsonIgnoreAttribute ignoreAttribute) { if (ignoreAttribute.Condition == JsonIgnoreCondition.Always) @@ -46,13 +54,21 @@ internal static List GetPropertiesForType(Type type) } var customConverterAttribute = prop.GetCustomAttribute(typeof(JsonConverterAttribute), false) as JsonConverterAttribute; + Type customConverterType = customConverterAttribute?.ConverterType; + + JsonNumberHandling? numberHandling = null; + if (prop.GetCustomAttribute(typeof(JsonNumberHandlingAttribute), false) is JsonNumberHandlingAttribute numberHandlingAttribute) + { + numberHandling = numberHandlingAttribute.Handling; + } propsToSerialize.Add(new SerializablePropertyInfo() { PropertyInfo = prop, - JsonPropertyName = propertyNameAttribute.Name, + JsonPropertyName = jsonPropertyName, IgnoreCondition = ignoreCondition, - CustomConverterType = customConverterAttribute?.ConverterType, + CustomConverterType = customConverterType, + NumberHandling = numberHandling, }); } @@ -60,6 +76,72 @@ internal static List GetPropertiesForType(Type type) }); } + /// + /// Returns accessor info for the [JsonExtensionData] property on the type, or null + /// if the type has no such property. + /// + internal static ExtensionDataInfo GetExtensionDataPropertyForType(Type type) + { + return extensionDataCache.GetOrAdd(type, (key) => + { + var rawProps = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + foreach (var prop in rawProps) + { + if (prop.GetCustomAttribute(typeof(JsonExtensionDataAttribute), false) != null) + { + return new ExtensionDataInfo(prop); + } + } + + return null; + }); + } + + /// + /// Holds accessor info for a [JsonExtensionData] property. + /// The property must be IDictionary<string, object> or + /// IDictionary<string, JsonElement>. + /// + internal class ExtensionDataInfo + { + private static MethodInfo createGetDelegateMethod = typeof(SerializablePropertyInfo).GetMethod("CreateGetDelegate", BindingFlags.Static | BindingFlags.NonPublic); + private static MethodInfo createSetDelegateMethod = typeof(SerializablePropertyInfo).GetMethod("CreateSetDelegate", BindingFlags.Static | BindingFlags.NonPublic); + + private Func getDelegate = null; + private Action setDelegate = null; + + internal ExtensionDataInfo(PropertyInfo propertyInfo) + { + this.PropertyInfo = propertyInfo; + } + + internal PropertyInfo PropertyInfo { get; } + + internal object Get(object obj) + { + if (this.getDelegate == null) + { + var gm = this.PropertyInfo.GetGetMethod(true); + var getMethod = createGetDelegateMethod.MakeGenericMethod(this.PropertyInfo.DeclaringType, this.PropertyInfo.PropertyType); + this.getDelegate = (Func)getMethod.Invoke(null, new object[] { gm }); + } + + return this.getDelegate(obj); + } + + internal void Set(object obj, object value) + { + if (this.setDelegate == null) + { + var sm = this.PropertyInfo.GetSetMethod(true); + var setMethod = createSetDelegateMethod.MakeGenericMethod(this.PropertyInfo.DeclaringType, this.PropertyInfo.PropertyType); + this.setDelegate = (Action)setMethod.Invoke(null, new object[] { sm }); + } + + this.setDelegate(obj, value); + } + } + // Create the various methods stored in SerializablePropertyInfo // this uses heavy reflection so that our internals are typesafe // and that our converter interface is JsonConverter which @@ -93,6 +175,12 @@ internal class SerializablePropertyInfo internal Type CustomConverterType { get; set; } + /// + /// The number handling mode for this property, or null if + /// JsonNumberHandling is not found. + /// + internal JsonNumberHandling? NumberHandling { get; set; } + /// /// Gets the converter to use to convert this property, either /// a custom one from the attribute or the converter returned @@ -103,19 +191,59 @@ internal JsonConverter GetConverter(JsonSerializerOptions options) if (this.getConverter == null) { var customConverter = default(JsonConverter); + var customConverterFactory = default(JsonConverterFactory); + if (this.CustomConverterType != null) { - // this assumes any property-level JsonConverter attribute - // specifies a JsonConverter<> type and not a JsonConverterFactory - // type - var baseType = this.CustomConverterType.BaseType; - var cvtGenericMethod = getConverterForTypeMethod.MakeGenericMethod(baseType, baseType.GenericTypeArguments[0]); - customConverter = (JsonConverter)cvtGenericMethod.Invoke(null, new object[] { this.CustomConverterType }); + // Check if it's a JsonConverterFactory + if (this.CustomConverterType.BaseType == typeof(JsonConverterFactory)) + { + // For factories, store the factory instance + customConverterFactory = (JsonConverterFactory)Activator.CreateInstance(this.CustomConverterType); + } + else + { + // For regular converters, use the existing logic + var baseType = this.CustomConverterType.BaseType; + var cvtGenericMethod = getConverterForTypeMethod.MakeGenericMethod(baseType, baseType.GenericTypeArguments[0]); + customConverter = (JsonConverter)cvtGenericMethod.Invoke(null, new object[] { this.CustomConverterType }); + } } var defaultCvtGenericMethod = getDefaultConverterMethod.MakeGenericMethod(this.PropertyInfo.PropertyType); var getDefaultConverter = (Func>)defaultCvtGenericMethod.Invoke(null, new object[] { this.PropertyInfo.PropertyType }); - this.getConverter = options => customConverter ?? getDefaultConverter(options); + this.getConverter = options => + { + if (customConverterFactory != null) + { + // Create converter from factory and wrap it in an adapter + var converter = customConverterFactory.CreateConverter(this.PropertyInfo.PropertyType, options); + var converterType = converter.GetType(); + + // Find the JsonConverter base class to get the T type + Type baseType = converterType; + while (baseType != null && (!baseType.IsGenericType || baseType.GetGenericTypeDefinition() != typeof(JsonConverter<>))) + { + baseType = baseType.BaseType; + } + + if (baseType != null) + { + var valueType = baseType.GetGenericArguments()[0]; + var adapterType = typeof(JsonConverterAdapter<,>).MakeGenericType(converterType, valueType); + return (JsonConverter)Activator.CreateInstance( + adapterType, + BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, + null, + new object[] { converter }, + null); + } + + throw new InvalidOperationException($"Unable to determine value type for converter {converterType}"); + } + + return customConverter ?? getDefaultConverter(options); + }; } return this.getConverter(options); @@ -206,4 +334,3 @@ public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOp } } } -#endif diff --git a/src/Stripe.net/Infrastructure/Public/AppInfo.cs b/src/Stripe.net/Infrastructure/Public/AppInfo.cs index 98c4655a97..6662868cce 100644 --- a/src/Stripe.net/Infrastructure/Public/AppInfo.cs +++ b/src/Stripe.net/Infrastructure/Public/AppInfo.cs @@ -2,9 +2,7 @@ namespace Stripe { using System.Text; using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif /// /// Contains information about the "app" which this integration belongs to. This should be @@ -14,32 +12,24 @@ public class AppInfo { /// Gets or sets the name of your application (e.g. "MyAwesomeApp"). [JsonProperty("name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("name")] -#endif public string Name { get; set; } /// /// Gets or sets your Stripe Partner ID (e.g. "pp_partner_1234"), if you have one. /// [JsonProperty("partner_id")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("partner_id")] -#endif public string PartnerId { get; set; } /// Gets or sets the version of your application (e.g. "1.2.34"). [JsonProperty("version")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("version")] -#endif public string Version { get; set; } /// Gets or sets the website for your application (e.g. "https://myawesomeapp.info"). [JsonProperty("url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("url")] -#endif public string Url { get; set; } /// diff --git a/src/Stripe.net/Infrastructure/Public/LiveApiRequestor.cs b/src/Stripe.net/Infrastructure/Public/LiveApiRequestor.cs index e478935b8b..00ef14a379 100644 --- a/src/Stripe.net/Infrastructure/Public/LiveApiRequestor.cs +++ b/src/Stripe.net/Infrastructure/Public/LiveApiRequestor.cs @@ -6,10 +6,10 @@ namespace Stripe using System.Linq; using System.Net; using System.Net.Http; + using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; - using Newtonsoft.Json.Linq; using Stripe.Infrastructure; /// Primary implementation of the ApiRequestor abstract class. @@ -44,7 +44,9 @@ public LiveApiRequestor(StripeClientOptions options, List defaultUsage = this.FilesBase = options.FilesBase ?? DefaultFilesBase; this.MeterEventsBase = options.MeterEventsBase ?? DefaultMeterEventsBase; this.defaultUsage = defaultUsage ?? new List(); +#pragma warning disable CS0618 // Type or member is obsolete this.jsonSerializerSettings = StripeConfiguration.DefaultSerializerSettings(this); +#pragma warning restore CS0618 // Type or member is obsolete } /// Default base URL for Stripe's API. @@ -140,74 +142,87 @@ private static IHttpClient BuildDefaultHttpClient() return new SystemNetHttpClient(); } - private static StripeException BuildV2StripeException(StripeResponse response) + private static StripeException BuildInvalidResponseException(StripeResponse response) { - JObject jObject = null; + return new StripeException( + response.StatusCode, + null, + $"Invalid response object from API: \"{response.Content}\"") + { + StripeResponse = response, + }; + } + private static StripeException BuildStripeException(StripeResponse response) + { + JsonDocument document; try { - jObject = JObject.Parse(response.Content); + document = JsonDocument.Parse(response.Content); } - catch (Newtonsoft.Json.JsonException) + catch (System.Text.Json.JsonException) { return BuildInvalidResponseException(response); } - JToken error = (JToken)jObject["error"]; - string type = (string)error["type"]; - return StripeException.ParseV2Exception( - type, - response, - error) ?? BuildStripeException(response); + using (document) + { + var root = document.RootElement; + + // If the value of the `error` key is a string, then the error is an OAuth error + // and we instantiate the StripeError object with the entire JSON. + // Otherwise, it's a regular API error and we instantiate the StripeError object + // with just the nested hash contained in the `error` key. + if (!root.TryGetProperty("error", out var errorElement)) + { + return BuildInvalidResponseException(response); + } + + var stripeError = errorElement.ValueKind == JsonValueKind.String + ? StripeError.FromJson(response.Content) + : StripeError.FromJson(errorElement); + + stripeError.StripeResponse = response; + + return new StripeException( + response.StatusCode, + stripeError, + stripeError.Message ?? stripeError.ErrorDescription) + { + StripeResponse = response, + }; + } } - private static StripeException BuildStripeException(StripeResponse response) + private static StripeException BuildV2StripeException(StripeResponse response) { - JObject jObject = null; - + JsonDocument document; try { - jObject = JObject.Parse(response.Content); + document = JsonDocument.Parse(response.Content); } - catch (Newtonsoft.Json.JsonException) + catch (System.Text.Json.JsonException) { return BuildInvalidResponseException(response); } - // If the value of the `error` key is a string, then the error is an OAuth error - // and we instantiate the StripeError object with the entire JSON. - // Otherwise, it's a regular API error and we instantiate the StripeError object - // with just the nested hash contained in the `error` key. - var errorToken = jObject["error"]; - if (errorToken == null) + using (document) { - return BuildInvalidResponseException(response); - } - - var stripeError = errorToken.Type == JTokenType.String - ? StripeError.FromJson(response.Content) - : StripeError.FromJson(errorToken.ToString()); - - stripeError.StripeResponse = response; + var root = document.RootElement; + if (!root.TryGetProperty("error", out var errorElement)) + { + return BuildInvalidResponseException(response); + } - return new StripeException( - response.StatusCode, - stripeError, - stripeError.Message ?? stripeError.ErrorDescription) - { - StripeResponse = response, - }; - } + string type = null; + if (errorElement.TryGetProperty("type", out var typeElement)) + { + type = typeElement.GetString(); + } - private static StripeException BuildInvalidResponseException(StripeResponse response) - { - return new StripeException( - response.StatusCode, - null, - $"Invalid response object from API: \"{response.Content}\"") - { - StripeResponse = response, - }; + return StripeException.ParseV2Exception(type, response, errorElement) + ?? BuildStripeException(response); + } } // Note: BaseOptions options really means query params here @@ -262,15 +277,32 @@ private T ProcessResponse(StripeResponse response, ApiMode apiMode) T obj; try { - obj = StripeEntity.FromJson(response.Content, this.jsonSerializerSettings); + obj = System.Text.Json.JsonSerializer.Deserialize( + response.Content, StripeConfiguration.SerializerOptions); } - catch (Newtonsoft.Json.JsonException) + catch (System.Text.Json.JsonException) { - throw BuildInvalidResponseException(response); + throw new StripeException( + response.StatusCode, + null, + $"Invalid response object from API: \"{response.Content}\"") + { + StripeResponse = response, + }; } obj.StripeResponse = response; + // Some deserialized types need a reference to the requestor (e.g. V2 + // events use it to fetch related objects). Since STJ converters have no + // mechanism to pass ambient state during deserialization, we set it here + // after the fact. If a new type needs the requestor, add a check below + // and ensure the type exposes an internal Requestor property. + if (obj is V2.Core.Event v2Event) + { + v2Event.Requestor = this; + } + return obj; } diff --git a/src/Stripe.net/Infrastructure/Public/RequestTelemetry.cs b/src/Stripe.net/Infrastructure/Public/RequestTelemetry.cs index 184628b8b2..c6f0a7c785 100644 --- a/src/Stripe.net/Infrastructure/Public/RequestTelemetry.cs +++ b/src/Stripe.net/Infrastructure/Public/RequestTelemetry.cs @@ -6,11 +6,8 @@ namespace Stripe using System.Linq; using System.Net.Http; using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; /// /// Helper class used by to manage request telemetry. @@ -94,30 +91,22 @@ public void MaybeEnqueueMetrics(HttpResponseMessage response, TimeSpan duration, private class ClientTelemetryPayload { [JsonProperty("last_request_metrics")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("last_request_metrics")] -#endif public RequestMetrics LastRequestMetrics { get; set; } } private class RequestMetrics { [JsonProperty("request_id")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("request_id")] -#endif public string RequestId { get; set; } [JsonProperty("request_duration_ms")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("request_duration_ms")] -#endif public long RequestDurationMs { get; set; } [JsonProperty("usage")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("usage")] -#endif public List Usage { get; set; } } } diff --git a/src/Stripe.net/Infrastructure/Public/StripeClient.cs b/src/Stripe.net/Infrastructure/Public/StripeClient.cs index f7bfdddcbf..3fcac1a9a2 100644 --- a/src/Stripe.net/Infrastructure/Public/StripeClient.cs +++ b/src/Stripe.net/Infrastructure/Public/StripeClient.cs @@ -26,7 +26,9 @@ public class StripeClient : IStripeClient internal StripeClient(ApiRequestor requestor) { this.Requestor = requestor; +#pragma warning disable CS0618 // Type or member is obsolete this.jsonSerializerSettings = StripeConfiguration.DefaultSerializerSettings(requestor); +#pragma warning restore CS0618 // Type or member is obsolete } /// Initializes a new instance of the class. diff --git a/src/Stripe.net/Infrastructure/Public/StripeConfiguration.cs b/src/Stripe.net/Infrastructure/Public/StripeConfiguration.cs index 6ee55f4a07..aafad11950 100644 --- a/src/Stripe.net/Infrastructure/Public/StripeConfiguration.cs +++ b/src/Stripe.net/Infrastructure/Public/StripeConfiguration.cs @@ -4,6 +4,8 @@ namespace Stripe using System.Collections.Generic; using System.Configuration; using System.Runtime.Serialization; + using System.Text.Json; + using System.Text.Json.Serialization; using Newtonsoft.Json; using Stripe.Infrastructure; @@ -98,7 +100,23 @@ public static string ClientId /// otherwise Stripe.net will no longer be able to deserialize polymorphic resources /// represented by interfaces (e.g. ). /// + [Obsolete("Use SerializerOptions instead. SerializerSettings will be removed in a future major version.")] +#pragma warning disable CS0618 // Type or member is obsolete public static JsonSerializerSettings SerializerSettings { get; set; } = DefaultSerializerSettings(); +#pragma warning restore CS0618 // Type or member is obsolete + + /// + /// Gets or sets the System.Text.Json options used for serialization and deserialization. + /// + public static JsonSerializerOptions SerializerOptions { get; set; } = DefaultStjSerializerOptions(); + + /// + /// Cached options instance for indented JSON output (used by ToJson()). + /// + internal static JsonSerializerOptions IndentedSerializerOptions { get; } = new JsonSerializerOptions(DefaultStjSerializerOptions()) + { + WriteIndented = true, + }; /// /// Gets or sets the maximum number of times that the library will retry requests that @@ -199,6 +217,7 @@ public static AppInfo AppInfo /// the default settings used by Stripe.net. /// /// A instance. + [Obsolete("Use DefaultStjSerializerOptions() instead. DefaultSerializerSettings() will be removed in a future major version.")] public static JsonSerializerSettings DefaultSerializerSettings() { return DefaultSerializerSettings(null); @@ -219,7 +238,7 @@ internal static JsonSerializerSettings DefaultSerializerSettings(ApiRequestor re // Re-enable the warning. #pragma warning restore SYSLIB0050 - Converters = new List + Converters = new List { new StripeObjectConverter(), }, @@ -242,6 +261,25 @@ public static void SetApiKey(string newApiKey) ApiKey = newApiKey; } + /// + /// Returns a new instance of with + /// the default settings used by Stripe.net for System.Text.Json serialization. + /// + /// A instance. + public static JsonSerializerOptions DefaultStjSerializerOptions() + { + return new JsonSerializerOptions + { + PropertyNameCaseInsensitive = false, + MaxDepth = 128, + ReadCommentHandling = JsonCommentHandling.Disallow, + AllowTrailingCommas = false, + DefaultIgnoreCondition = JsonIgnoreCondition.Never, + + Converters = { }, + }; + } + private static IStripeClient BuildDefaultStripeClient() { if (ApiKey != null && ApiKey.Length == 0) diff --git a/src/Stripe.net/Infrastructure/Public/StripeException.cs b/src/Stripe.net/Infrastructure/Public/StripeException.cs index 751f5cd577..ead5548a2f 100644 --- a/src/Stripe.net/Infrastructure/Public/StripeException.cs +++ b/src/Stripe.net/Infrastructure/Public/StripeException.cs @@ -2,7 +2,7 @@ namespace Stripe { using System; using System.Net; - using Newtonsoft.Json.Linq; + using System.Text.Json; public class StripeException : Exception { @@ -40,13 +40,17 @@ internal StripeException(HttpStatusCode httpStatusCode, StripeError stripeError) public StripeResponse StripeResponse { get; set; } - internal static StripeException ParseV2Exception(string type, StripeResponse response, JToken body) + internal static StripeException ParseV2Exception(string type, StripeResponse response, JsonElement body) { var httpStatusCode = response.StatusCode; StripeException ret; switch (type) { // The beginning of the section generated from our OpenAPI spec + case "rate_limit": + ret = Stripe.V2.RateLimitException.Parse(httpStatusCode, body); + break; + case "temporary_session_expired": ret = Stripe.V2.TemporarySessionExpiredException.Parse(httpStatusCode, body); break; diff --git a/src/Stripe.net/Infrastructure/Public/StripeRequest.cs b/src/Stripe.net/Infrastructure/Public/StripeRequest.cs index a73ee259d1..8c332871f9 100644 --- a/src/Stripe.net/Infrastructure/Public/StripeRequest.cs +++ b/src/Stripe.net/Infrastructure/Public/StripeRequest.cs @@ -201,6 +201,11 @@ private static Dictionary BuildStripeHeaders( stripeHeaders.Add("Stripe-Context", requestOptions.StripeContext); } + if (!string.IsNullOrEmpty(requestOptions?.StripeRequestTrigger)) + { + stripeHeaders.Add("Stripe-Request-Trigger", requestOptions.StripeRequestTrigger); + } + if (!string.IsNullOrEmpty(requestOptions?.IdempotencyKey)) { stripeHeaders.Add("Idempotency-Key", requestOptions.IdempotencyKey); diff --git a/src/Stripe.net/Infrastructure/Public/StripeTypeRegistry.cs b/src/Stripe.net/Infrastructure/Public/StripeTypeRegistry.cs index 1725ecacba..0b002eefc3 100644 --- a/src/Stripe.net/Infrastructure/Public/StripeTypeRegistry.cs +++ b/src/Stripe.net/Infrastructure/Public/StripeTypeRegistry.cs @@ -131,6 +131,9 @@ public static class StripeTypeRegistry { "refund", typeof(Refund) }, { "reporting.report_run", typeof(Reporting.ReportRun) }, { "reporting.report_type", typeof(Reporting.ReportType) }, + { "reserve.hold", typeof(Reserve.Hold) }, + { "reserve.plan", typeof(Reserve.Plan) }, + { "reserve.release", typeof(Reserve.Release) }, { "reserve_transaction", typeof(ReserveTransaction) }, { "review", typeof(Review) }, { "scheduled_query_run", typeof(Sigma.ScheduledQueryRun) }, diff --git a/src/Stripe.net/Infrastructure/Public/SystemNetHttpClient.cs b/src/Stripe.net/Infrastructure/Public/SystemNetHttpClient.cs index f13500c1fe..4017a7566f 100644 --- a/src/Stripe.net/Infrastructure/Public/SystemNetHttpClient.cs +++ b/src/Stripe.net/Infrastructure/Public/SystemNetHttpClient.cs @@ -62,6 +62,23 @@ private static readonly Lazy LazyDefaultHttpClient private string stripeClientUserAgentString; + internal static readonly (string EnvVar, string Slug)[] AIAgents = new (string EnvVar, string Slug)[] + { + // The beginning of the section generated from our OpenAPI spec + ("ANTIGRAVITY_CLI_ALIAS", "antigravity"), + ("CLAUDECODE", "claude_code"), + ("CLINE_ACTIVE", "cline"), + ("CODEX_SANDBOX", "codex_cli"), + ("CODEX_THREAD_ID", "codex_cli"), + ("CODEX_SANDBOX_NETWORK_DISABLED", "codex_cli"), + ("CODEX_CI", "codex_cli"), + ("CURSOR_AGENT", "cursor"), + ("GEMINI_CLI", "gemini_cli"), + ("OPENCODE", "open_code"), + + // The end of the section generated from our OpenAPI spec + }; + // Deprecated in .NET 9; but tls 1.2 became a default after .NET Framework 4.7 #if !NET9_0_OR_GREATER static SystemNetHttpClient() @@ -189,6 +206,25 @@ await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) }; } + private static string DetectAIAgent() + { + return DetectAIAgent(System.Environment.GetEnvironmentVariable); + } + + internal static string DetectAIAgent(Func getEnv) + { + foreach (var (envVar, slug) in AIAgents) + { + var val = getEnv(envVar); + if (!string.IsNullOrEmpty(val)) + { + return slug; + } + } + + return string.Empty; + } + private async Task<(HttpResponseMessage responseMessage, int retries)> SendHttpRequest( StripeRequest request, CancellationToken cancellationToken) @@ -262,7 +298,6 @@ private string BuildStripeClientUserAgentString() { { "bindings_version", StripeConfiguration.StripeNetVersion }, { "lang", ".net" }, - { "publisher", "stripe" }, { "stripe_net_target_framework", StripeNetTargetFramework }, }; @@ -279,13 +314,18 @@ private string BuildStripeClientUserAgentString() values.Add("lang_version", "(unknown)"); } - try - { - values.Add("os_version", RuntimeInformation.GetOSVersion()); - } - catch (Exception) + if (this.EnableTelemetry) { - values.Add("os_version", "(unknown)"); + try + { + values.Add( + "platform", + $"{Environment.OSVersion} {System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture}"); + } + catch (Exception) + { + values.Add("platform", "(unknown)"); + } } try @@ -302,6 +342,12 @@ private string BuildStripeClientUserAgentString() values.Add("application", this.appInfo); } + var aiAgent = DetectAIAgent(); + if (!string.IsNullOrEmpty(aiAgent)) + { + values.Add("ai_agent", aiAgent); + } + return JsonUtils.SerializeObject(values, Formatting.None); } @@ -314,6 +360,12 @@ private string BuildUserAgentString(ApiMode apiMode) userAgent += " " + this.appInfo.FormatUserAgent(); } + var aiAgent = DetectAIAgent(); + if (!string.IsNullOrEmpty(aiAgent)) + { + userAgent += $" AIAgent/{aiAgent}"; + } + return userAgent; } diff --git a/src/Stripe.net/Services/BankAccounts/BankAccountCreateOptions.cs b/src/Stripe.net/Services/BankAccounts/BankAccountCreateOptions.cs index 921e3f10df..8dcd02ca81 100644 --- a/src/Stripe.net/Services/BankAccounts/BankAccountCreateOptions.cs +++ b/src/Stripe.net/Services/BankAccounts/BankAccountCreateOptions.cs @@ -2,26 +2,19 @@ namespace Stripe { using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; public class BankAccountCreateOptions : BaseOptions, IHasMetadata { [JsonProperty("metadata")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("metadata")] -#endif public Dictionary Metadata { get; set; } [JsonProperty("source")] [JsonConverter(typeof(AnyOfConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("source")] [STJS.JsonConverter(typeof(STJAnyOfConverter))] -#endif public AnyOf Source { get; set; } } } diff --git a/src/Stripe.net/Services/BankAccounts/BankAccountListOptions.cs b/src/Stripe.net/Services/BankAccounts/BankAccountListOptions.cs index d54d0121b2..fed9eb8bbb 100644 --- a/src/Stripe.net/Services/BankAccounts/BankAccountListOptions.cs +++ b/src/Stripe.net/Services/BankAccounts/BankAccountListOptions.cs @@ -1,20 +1,14 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using Stripe.Infrastructure; using STJS = System.Text.Json.Serialization; -#endif -#if NET6_0_OR_GREATER - [STJS.JsonConverter(typeof(STJMemberSerializationOptIn))] -#endif + [STJS.JsonConverter(typeof(STJStripeOptionsConverter))] public class BankAccountListOptions : ListOptions { [JsonProperty("object")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("object")] -#endif internal string Object => "bank_account"; } } diff --git a/src/Stripe.net/Services/Cards/CardCreateOptions.cs b/src/Stripe.net/Services/Cards/CardCreateOptions.cs index dc6ad9e84d..4cb37075d6 100644 --- a/src/Stripe.net/Services/Cards/CardCreateOptions.cs +++ b/src/Stripe.net/Services/Cards/CardCreateOptions.cs @@ -2,38 +2,27 @@ namespace Stripe { using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; public class CardCreateOptions : BaseOptions, IHasMetadata { [JsonProperty("default_for_currency")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("default_for_currency")] -#endif public bool? DefaultForCurrency { get; set; } [JsonProperty("metadata")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("metadata")] -#endif public Dictionary Metadata { get; set; } [JsonProperty("source")] [JsonConverter(typeof(AnyOfConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("source")] [STJS.JsonConverter(typeof(STJAnyOfConverter))] -#endif public AnyOf Source { get; set; } [JsonProperty("validate")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("validate")] -#endif public bool? Validate { get; set; } } } diff --git a/src/Stripe.net/Services/Cards/CardListOptions.cs b/src/Stripe.net/Services/Cards/CardListOptions.cs index 2c5b2b99ee..d13b7b61f0 100644 --- a/src/Stripe.net/Services/Cards/CardListOptions.cs +++ b/src/Stripe.net/Services/Cards/CardListOptions.cs @@ -1,20 +1,14 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using Stripe.Infrastructure; using STJS = System.Text.Json.Serialization; -#endif -#if NET6_0_OR_GREATER - [STJS.JsonConverter(typeof(STJMemberSerializationOptIn))] -#endif + [STJS.JsonConverter(typeof(STJStripeOptionsConverter))] public class CardListOptions : ListOptions { [JsonProperty("object")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("object")] -#endif internal string Object => "card"; } } diff --git a/src/Stripe.net/Services/Charges/ChargeSourceListOptions.cs b/src/Stripe.net/Services/Charges/ChargeSourceListOptions.cs index aaa43eb6fb..778e8002d7 100644 --- a/src/Stripe.net/Services/Charges/ChargeSourceListOptions.cs +++ b/src/Stripe.net/Services/Charges/ChargeSourceListOptions.cs @@ -1,16 +1,12 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class ChargeSourceListOptions : INestedOptions, IHasObject { [JsonProperty("object")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("object")] -#endif public string Object { get; set; } } } diff --git a/src/Stripe.net/Services/CreditNotes/CreditNoteListPreviewLineItemsOptions.cs b/src/Stripe.net/Services/CreditNotes/CreditNoteListPreviewLineItemsOptions.cs index 6923fc8751..ff8c1655a7 100644 --- a/src/Stripe.net/Services/CreditNotes/CreditNoteListPreviewLineItemsOptions.cs +++ b/src/Stripe.net/Services/CreditNotes/CreditNoteListPreviewLineItemsOptions.cs @@ -3,66 +3,45 @@ namespace Stripe using System; using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; public class CreditNoteListPreviewLineItemsOptions : ListOptions, IHasMetadata { [JsonProperty("amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("amount")] -#endif public long? Amount { get; set; } [JsonProperty("credit_amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("credit_amount")] -#endif public long? CreditAmount { get; set; } [JsonProperty("invoice")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("invoice")] -#endif public string Invoice { get; set; } [JsonProperty("memo")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("memo")] -#endif public string Memo { get; set; } [JsonProperty("metadata")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("metadata")] -#endif public Dictionary Metadata { get; set; } [JsonProperty("out_of_band_amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("out_of_band_amount")] -#endif public long? OutOfBandAmount { get; set; } [JsonProperty("reason")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("reason")] -#endif public string Reason { get; set; } [JsonProperty("refund")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("refund")] -#endif public string Refund { get; set; } [JsonProperty("refund_amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("refund_amount")] -#endif public long? RefundAmount { get; set; } } } diff --git a/src/Stripe.net/Services/Events/EventUtility.cs b/src/Stripe.net/Services/Events/EventUtility.cs index 657800cc77..27e807227a 100644 --- a/src/Stripe.net/Services/Events/EventUtility.cs +++ b/src/Stripe.net/Services/Events/EventUtility.cs @@ -65,9 +65,9 @@ public static bool IsCompatibleApiVersion(string eventApiVersion) /// public static Event ParseEvent(string json, bool throwOnApiVersionMismatch = true) { - var stripeEvent = JsonUtils.DeserializeObject( + var stripeEvent = System.Text.Json.JsonSerializer.Deserialize( json, - StripeConfiguration.SerializerSettings); + StripeConfiguration.SerializerOptions); if (throwOnApiVersionMismatch && !IsCompatibleApiVersion(stripeEvent.ApiVersion)) diff --git a/src/Stripe.net/Services/InvoiceLineItems/InvoiceUpdateInvoiceLineItemsOptions.cs b/src/Stripe.net/Services/InvoiceLineItems/InvoiceUpdateInvoiceLineItemsOptions.cs index d434a93617..3f98a56f4e 100644 --- a/src/Stripe.net/Services/InvoiceLineItems/InvoiceUpdateInvoiceLineItemsOptions.cs +++ b/src/Stripe.net/Services/InvoiceLineItems/InvoiceUpdateInvoiceLineItemsOptions.cs @@ -3,9 +3,7 @@ namespace Stripe using System; using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif [Obsolete("Use InvoiceLineItemUpdateOptions instead.")] public class InvoiceUpdateInvoiceLineItemsOptions : BaseOptions, IHasMetadata @@ -16,9 +14,7 @@ public class InvoiceUpdateInvoiceLineItemsOptions : BaseOptions, IHasMetadata /// negative amount. /// [JsonProperty("amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("amount")] -#endif public long? Amount { get; set; } /// @@ -26,9 +22,7 @@ public class InvoiceUpdateInvoiceLineItemsOptions : BaseOptions, IHasMetadata /// displayed in the invoice for easy tracking. /// [JsonProperty("description")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("description")] -#endif public string Description { get; set; } /// @@ -37,9 +31,7 @@ public class InvoiceUpdateInvoiceLineItemsOptions : BaseOptions, IHasMetadata /// prorations. /// [JsonProperty("discountable")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("discountable")] -#endif public bool? Discountable { get; set; } /// @@ -48,9 +40,7 @@ public class InvoiceUpdateInvoiceLineItemsOptions : BaseOptions, IHasMetadata /// previously-defined discounts. /// [JsonProperty("discounts")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("discounts")] -#endif public List Discounts { get; set; } /// @@ -65,9 +55,7 @@ public class InvoiceUpdateInvoiceLineItemsOptions : BaseOptions, IHasMetadata /// items, where any existing metadata on the invoice line is merged with the incoming data. /// [JsonProperty("metadata")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("metadata")] -#endif public Dictionary Metadata { get; set; } /// @@ -79,18 +67,14 @@ public class InvoiceUpdateInvoiceLineItemsOptions : BaseOptions, IHasMetadata /// Recognition documentation for details. /// [JsonProperty("period")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("period")] -#endif public InvoiceLineItemPeriodOptions Period { get; set; } /// /// The ID of the price object. One of price or price_data is required. /// [JsonProperty("price")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("price")] -#endif public string Price { get; set; } /// @@ -98,18 +82,14 @@ public class InvoiceUpdateInvoiceLineItemsOptions : BaseOptions, IHasMetadata /// object inline. One of price or price_data is required. /// [JsonProperty("price_data")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("price_data")] -#endif public InvoiceLineItemPriceDataOptions PriceData { get; set; } /// /// Non-negative integer. The quantity of units for the line item. /// [JsonProperty("quantity")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("quantity")] -#endif public long? Quantity { get; set; } /// @@ -123,9 +103,7 @@ public class InvoiceUpdateInvoiceLineItemsOptions : BaseOptions, IHasMetadata /// string to remove previously defined tax amounts. /// [JsonProperty("tax_amounts")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("tax_amounts")] -#endif public List TaxAmounts { get; set; } /// @@ -134,9 +112,7 @@ public class InvoiceUpdateInvoiceLineItemsOptions : BaseOptions, IHasMetadata /// previously-defined tax rates. /// [JsonProperty("tax_rates")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("tax_rates")] -#endif public List TaxRates { get; set; } } } diff --git a/src/Stripe.net/Services/Invoices/InvoiceLineItemListOptions.cs b/src/Stripe.net/Services/Invoices/InvoiceLineItemListOptions.cs index 3694ea93b5..72cb18e73c 100644 --- a/src/Stripe.net/Services/Invoices/InvoiceLineItemListOptions.cs +++ b/src/Stripe.net/Services/Invoices/InvoiceLineItemListOptions.cs @@ -2,34 +2,24 @@ namespace Stripe { using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class InvoiceLineItemListOptions : ListOptions { [JsonProperty("coupon")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("coupon")] -#endif public string Coupon { get; set; } [JsonProperty("customer")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("customer")] -#endif public string Customer { get; set; } [JsonProperty("subscription")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("subscription")] -#endif public string Subscription { get; set; } [JsonProperty("subscription_plan")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("subscription_plan")] -#endif public string SubscriptionPlan { get; set; } } } diff --git a/src/Stripe.net/Services/Invoices/InvoiceListLineItemsOptions.cs b/src/Stripe.net/Services/Invoices/InvoiceListLineItemsOptions.cs index a82bd0b6b3..a00cae8dfc 100644 --- a/src/Stripe.net/Services/Invoices/InvoiceListLineItemsOptions.cs +++ b/src/Stripe.net/Services/Invoices/InvoiceListLineItemsOptions.cs @@ -3,35 +3,25 @@ namespace Stripe using System; using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif [Obsolete("Use InvoiceLineItemListOptions instead.")] public class InvoiceListLineItemsOptions : ListOptions { [JsonProperty("coupon")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("coupon")] -#endif public string Coupon { get; set; } [JsonProperty("customer")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("customer")] -#endif public string Customer { get; set; } [JsonProperty("subscription")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("subscription")] -#endif public string Subscription { get; set; } [JsonProperty("subscription_plan")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("subscription_plan")] -#endif public string SubscriptionPlan { get; set; } } } diff --git a/src/Stripe.net/Services/Invoices/InvoiceUpcomingInvoiceItemOptions.cs b/src/Stripe.net/Services/Invoices/InvoiceUpcomingInvoiceItemOptions.cs index c7d757e59d..94a7d27489 100644 --- a/src/Stripe.net/Services/Invoices/InvoiceUpcomingInvoiceItemOptions.cs +++ b/src/Stripe.net/Services/Invoices/InvoiceUpcomingInvoiceItemOptions.cs @@ -2,97 +2,69 @@ namespace Stripe { using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; + [STJS.JsonConverter(typeof(STJStripeOptionsConverter))] public class InvoiceUpcomingInvoiceItemOptions : INestedOptions, IHasMetadata { [JsonProperty("amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("amount")] -#endif public long? Amount { get; set; } [JsonProperty("currency")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("currency")] -#endif public string Currency { get; set; } [JsonProperty("description")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("description")] -#endif public string Description { get; set; } [JsonProperty("discountable")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("discountable")] -#endif public bool? Discountable { get; set; } [JsonProperty("discounts")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("discounts")] -#endif public List Discounts { get; set; } [JsonProperty("invoiceitem")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("invoiceitem")] -#endif [AllowNameMismatch] public string InvoiceItem { get; set; } [JsonProperty("metadata")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("metadata")] -#endif public Dictionary Metadata { get; set; } [JsonProperty("period")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("period")] -#endif public InvoiceItemPeriodOptions Period { get; set; } [JsonProperty("price")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("price")] -#endif public string Price { get; set; } [JsonProperty("price_data")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("price_data")] -#endif public InvoiceItemPriceDataOptions PriceData { get; set; } [JsonProperty("quantity")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("quantity")] -#endif public long? Quantity { get; set; } [JsonProperty("tax_rates")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("tax_rates")] -#endif public List TaxRates { get; set; } [JsonProperty("unit_amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("unit_amount")] -#endif public long? UnitAmount { get; set; } + [JsonConverter(typeof(DecimalStringConverter))] [JsonProperty("unit_amount_decimal")] -#if NET6_0_OR_GREATER + [STJS.JsonNumberHandling(STJS.JsonNumberHandling.AllowReadingFromString | STJS.JsonNumberHandling.WriteAsString)] [STJS.JsonPropertyName("unit_amount_decimal")] -#endif public decimal? UnitAmountDecimal { get; set; } } } diff --git a/src/Stripe.net/Services/OAuth/OAuthAuthorizeUrlOptions.cs b/src/Stripe.net/Services/OAuth/OAuthAuthorizeUrlOptions.cs index d43ab0e537..e11685b92b 100644 --- a/src/Stripe.net/Services/OAuth/OAuthAuthorizeUrlOptions.cs +++ b/src/Stripe.net/Services/OAuth/OAuthAuthorizeUrlOptions.cs @@ -2,9 +2,7 @@ namespace Stripe { using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class OAuthAuthorizeUrlOptions : BaseOptions { @@ -13,9 +11,7 @@ public class OAuthAuthorizeUrlOptions : BaseOptions /// already connected. Defaults to false. /// [JsonProperty("always_prompt")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("always_prompt")] -#endif public bool? AlwaysPrompt { get; set; } /// @@ -23,16 +19,12 @@ public class OAuthAuthorizeUrlOptions : BaseOptions /// application settings. /// [JsonProperty("client_id")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("client_id")] -#endif public string ClientId { get; set; } /// The only option at the moment is code. [JsonProperty("response_type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("response_type")] -#endif public string ResponseType { get; set; } = "code"; /// @@ -52,9 +44,7 @@ public class OAuthAuthorizeUrlOptions : BaseOptions /// /// [JsonProperty("redirect_uri")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("redirect_uri")] -#endif public string RedirectUri { get; set; } /// @@ -62,18 +52,14 @@ public class OAuthAuthorizeUrlOptions : BaseOptions /// Defaults to read_only. /// [JsonProperty("scope")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("scope")] -#endif public string Scope { get; set; } /// /// An arbitrary string value we will pass back to you, useful for CSRF protection. /// [JsonProperty("state")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("state")] -#endif public string State { get; set; } /// @@ -89,16 +75,12 @@ public class OAuthAuthorizeUrlOptions : BaseOptions /// /// [JsonProperty("stripe_landing")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("stripe_landing")] -#endif public string StripeLanding { get; set; } /// Prefilled details in the account form for new users. [JsonProperty("stripe_user")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("stripe_user")] -#endif public OAuthAuthorizeUrlStripeUserOptions StripeUser { get; set; } /// @@ -110,9 +92,7 @@ public class OAuthAuthorizeUrlOptions : BaseOptions /// parameter in your OAuth link. /// [JsonProperty("suggested_capabilities")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("suggested_capabilities")] -#endif public List SuggestedCapabilities { get; set; } } } diff --git a/src/Stripe.net/Services/OAuth/OAuthAuthorizeUrlStripeUserOptions.cs b/src/Stripe.net/Services/OAuth/OAuthAuthorizeUrlStripeUserOptions.cs index cf8f612d94..eb5099a758 100644 --- a/src/Stripe.net/Services/OAuth/OAuthAuthorizeUrlStripeUserOptions.cs +++ b/src/Stripe.net/Services/OAuth/OAuthAuthorizeUrlStripeUserOptions.cs @@ -1,9 +1,7 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions { @@ -15,9 +13,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("block_kana")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("block_kana")] -#endif public string BlockKana { get; set; } /// @@ -28,9 +24,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("block_kanji")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("block_kanji")] -#endif public string BlockKanji { get; set; } /// @@ -41,9 +35,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("building_kana")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("building_kana")] -#endif public string BuildingKana { get; set; } /// @@ -54,16 +46,12 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("building_kanji")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("building_kanji")] -#endif public string BuildingKanji { get; set; } /// The legal name of the business, also used for the statement descriptor. [JsonProperty("business_name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("business_name")] -#endif public string BusinessName { get; set; } /// @@ -74,9 +62,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("business_type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("business_type")] -#endif public string BusinessType { get; set; } /// @@ -87,9 +73,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("city")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("city")] -#endif public string City { get; set; } /// @@ -97,9 +81,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// Must be a country that Stripe currently supports. /// [JsonProperty("country")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("country")] -#endif public string Country { get; set; } /// @@ -111,9 +93,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// Must prefill with the corresponding country. /// [JsonProperty("currency")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("currency")] -#endif public string Currency { get; set; } /// @@ -127,9 +107,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("dob_day")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("dob_day")] -#endif public long? DobDay { get; set; } /// @@ -143,9 +121,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("dob_month")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("dob_month")] -#endif public long? DobMonth { get; set; } /// @@ -159,24 +135,18 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("dob_year")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("dob_year")] -#endif public long? DobYear { get; set; } /// The user's email address. Must be a valid email format. /// Recommended. [JsonProperty("email")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("email")] -#endif public string Email { get; set; } /// First name of the person who will be filling out a Stripe application. [JsonProperty("first_name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("first_name")] -#endif public string FirstName { get; set; } /// @@ -190,9 +160,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("first_name_kana")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("first_name_kana")] -#endif public string FirstNameKana { get; set; } /// @@ -206,9 +174,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("first_name_kanji")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("first_name_kanji")] -#endif public string FirstNameKanji { get; set; } /// @@ -222,16 +188,12 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("gender")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("gender")] -#endif public string Gender { get; set; } /// Last name of the person who will be filling out a Stripe application. [JsonProperty("last_name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("last_name")] -#endif public string LastName { get; set; } /// @@ -245,9 +207,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("last_name_kana")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("last_name_kana")] -#endif public string LastNameKana { get; set; } /// @@ -261,9 +221,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("last_name_kanji")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("last_name_kanji")] -#endif public string LastNameKanji { get; set; } /// @@ -271,23 +229,17 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// Must also prefill with the corresponding country. /// [JsonProperty("phone_number")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("phone_number")] -#endif public string PhoneNumber { get; set; } /// true if the user sells a physical product, false otherwise. [JsonProperty("physical_product")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("physical_product")] -#endif public bool? PhysicalProduct { get; set; } /// A description of what the business is accepting payments for. [JsonProperty("product_description")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("product_description")] -#endif public string ProductDescription { get; set; } /// @@ -300,16 +252,12 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("state")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("state")] -#endif public string State { get; set; } /// Street address of the business. [JsonProperty("street_address")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("street_address")] -#endif public string StreetAddress { get; set; } /// @@ -330,9 +278,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// Recommended. [JsonProperty("url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("url")] -#endif public string Url { get; set; } /// @@ -343,9 +289,7 @@ public class OAuthAuthorizeUrlStripeUserOptions : INestedOptions /// /// [JsonProperty("zip")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("zip")] -#endif public string Zip { get; set; } } } diff --git a/src/Stripe.net/Services/OAuth/OAuthDeauthorizeOptions.cs b/src/Stripe.net/Services/OAuth/OAuthDeauthorizeOptions.cs index 6961cbb6e7..24e51a643f 100644 --- a/src/Stripe.net/Services/OAuth/OAuthDeauthorizeOptions.cs +++ b/src/Stripe.net/Services/OAuth/OAuthDeauthorizeOptions.cs @@ -1,9 +1,7 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class OAuthDeauthorizeOptions : BaseOptions { @@ -12,16 +10,12 @@ public class OAuthDeauthorizeOptions : BaseOptions /// The account must be connected to this application. /// [JsonProperty("client_id")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("client_id")] -#endif public string ClientId { get; set; } /// The account you'd like to disconnect from. [JsonProperty("stripe_user_id")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("stripe_user_id")] -#endif public string StripeUserId { get; set; } } } diff --git a/src/Stripe.net/Services/OAuth/OAuthTokenCreateOptions.cs b/src/Stripe.net/Services/OAuth/OAuthTokenCreateOptions.cs index 4b24d55ebe..9ed4e7656d 100644 --- a/src/Stripe.net/Services/OAuth/OAuthTokenCreateOptions.cs +++ b/src/Stripe.net/Services/OAuth/OAuthTokenCreateOptions.cs @@ -2,9 +2,7 @@ namespace Stripe { using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class OAuthTokenCreateOptions : BaseOptions { @@ -19,9 +17,7 @@ public class OAuthTokenCreateOptions : BaseOptions /// with a failure. /// [JsonProperty("assert_capabilities")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("assert_capabilities")] -#endif public List AssertCapabilities { get; set; } /// @@ -30,16 +26,12 @@ public class OAuthTokenCreateOptions : BaseOptions /// depends on whether the client_id used was production or development). /// [JsonProperty("client_secret")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("client_secret")] -#endif public string ClientSecret { get; set; } /// The value of the code, depending on the grant_type. [JsonProperty("code")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("code")] -#endif public string Code { get; set; } /// @@ -47,16 +39,12 @@ public class OAuthTokenCreateOptions : BaseOptions /// refresh_token when using a refresh token to get a new access token. /// [JsonProperty("grant_type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("grant_type")] -#endif public string GrantType { get; set; } /// The value of the refresh_token, depending on the grant_type. [JsonProperty("refresh_token")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("refresh_token")] -#endif public string RefreshToken { get; set; } /// @@ -68,9 +56,7 @@ public class OAuthTokenCreateOptions : BaseOptions /// Defaults to the scope of the refresh token. /// [JsonProperty("scope")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("scope")] -#endif public string Scope { get; set; } } } diff --git a/src/Stripe.net/Services/Prices/PriceTransformUsageOptions.cs b/src/Stripe.net/Services/Prices/PriceTransformUsageOptions.cs index c4860f08a2..0c819fff97 100644 --- a/src/Stripe.net/Services/Prices/PriceTransformUsageOptions.cs +++ b/src/Stripe.net/Services/Prices/PriceTransformUsageOptions.cs @@ -1,22 +1,16 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class PriceTransformUsageOptions : INestedOptions { [JsonProperty("divide_by")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("divide_by")] -#endif public long? DivideBy { get; set; } [JsonProperty("round")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("round")] -#endif public string Round { get; set; } } } diff --git a/src/Stripe.net/Services/Products/PackageDimensionOptions.cs b/src/Stripe.net/Services/Products/PackageDimensionOptions.cs index 38599051cf..a629087560 100644 --- a/src/Stripe.net/Services/Products/PackageDimensionOptions.cs +++ b/src/Stripe.net/Services/Products/PackageDimensionOptions.cs @@ -2,34 +2,24 @@ namespace Stripe { using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class PackageDimensionOptions : INestedOptions { [JsonProperty("height")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("height")] -#endif public decimal? Height { get; set; } [JsonProperty("length")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("length")] -#endif public decimal? Length { get; set; } [JsonProperty("weight")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("weight")] -#endif public decimal? Weight { get; set; } [JsonProperty("width")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("width")] -#endif public decimal? Width { get; set; } } } diff --git a/src/Stripe.net/Services/Skus/InventoryOptions.cs b/src/Stripe.net/Services/Skus/InventoryOptions.cs index 38a210c9c6..30c5b59ee4 100644 --- a/src/Stripe.net/Services/Skus/InventoryOptions.cs +++ b/src/Stripe.net/Services/Skus/InventoryOptions.cs @@ -1,28 +1,20 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class InventoryOptions : INestedOptions { [JsonProperty("quantity")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("quantity")] -#endif public long? Quantity { get; set; } [JsonProperty("type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("type")] -#endif public string Type { get; set; } [JsonProperty("value")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("value")] -#endif public string Value { get; set; } } } diff --git a/src/Stripe.net/Services/Sources/SourceAcssDebitCreateOptions.cs b/src/Stripe.net/Services/Sources/SourceAcssDebitCreateOptions.cs index 16fac3d7d7..9402590494 100644 --- a/src/Stripe.net/Services/Sources/SourceAcssDebitCreateOptions.cs +++ b/src/Stripe.net/Services/Sources/SourceAcssDebitCreateOptions.cs @@ -1,28 +1,20 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SourceAcssDebitCreateOptions : INestedOptions { [JsonProperty("account_number")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("account_number")] -#endif public string AccountNumber { get; set; } [JsonProperty("category")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("category")] -#endif public string Category { get; set; } [JsonProperty("routing_number")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("routing_number")] -#endif public string RoutingNumber { get; set; } } } diff --git a/src/Stripe.net/Services/Sources/SourceAttachOptions.cs b/src/Stripe.net/Services/Sources/SourceAttachOptions.cs index 6ced21d8a9..234c41a59a 100644 --- a/src/Stripe.net/Services/Sources/SourceAttachOptions.cs +++ b/src/Stripe.net/Services/Sources/SourceAttachOptions.cs @@ -2,22 +2,16 @@ namespace Stripe { using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SourceAttachOptions : BaseOptions { [JsonProperty("source")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("source")] -#endif public string Source { get; set; } [JsonProperty("validate")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("validate")] -#endif public bool? Validate { get; set; } } } diff --git a/src/Stripe.net/Services/Sources/SourceAuBecsDebitCreateOptions.cs b/src/Stripe.net/Services/Sources/SourceAuBecsDebitCreateOptions.cs index a7b61fa29b..7b94484cf2 100644 --- a/src/Stripe.net/Services/Sources/SourceAuBecsDebitCreateOptions.cs +++ b/src/Stripe.net/Services/Sources/SourceAuBecsDebitCreateOptions.cs @@ -1,22 +1,16 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SourceAuBecsDebitCreateOptions : INestedOptions { [JsonProperty("account_number")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("account_number")] -#endif public string AccountNumber { get; set; } [JsonProperty("bsb_number")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("bsb_number")] -#endif public string BsbNumber { get; set; } } } diff --git a/src/Stripe.net/Services/Sources/SourceBancontactCreateOptions.cs b/src/Stripe.net/Services/Sources/SourceBancontactCreateOptions.cs index e3f9d2f77e..1a77764718 100644 --- a/src/Stripe.net/Services/Sources/SourceBancontactCreateOptions.cs +++ b/src/Stripe.net/Services/Sources/SourceBancontactCreateOptions.cs @@ -1,16 +1,12 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SourceBancontactCreateOptions : INestedOptions { [JsonProperty("preferred_language")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("preferred_language")] -#endif public string PreferredLanguage { get; set; } } } diff --git a/src/Stripe.net/Services/Sources/SourceCreateOptions.cs b/src/Stripe.net/Services/Sources/SourceCreateOptions.cs index 54b4ffbc97..da03cbd657 100644 --- a/src/Stripe.net/Services/Sources/SourceCreateOptions.cs +++ b/src/Stripe.net/Services/Sources/SourceCreateOptions.cs @@ -2,108 +2,73 @@ namespace Stripe { using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; public class SourceCreateOptions : BaseOptions, IHasMetadata { [JsonProperty("alipay")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("alipay")] -#endif public string Alipay { get; set; } [JsonProperty("amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("amount")] -#endif public long? Amount { get; set; } [JsonProperty("currency")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("currency")] -#endif public string Currency { get; set; } [JsonProperty("customer")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("customer")] -#endif public string Customer { get; set; } [JsonProperty("flow")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("flow")] -#endif public string Flow { get; set; } [JsonProperty("mandate")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("mandate")] -#endif public SourceMandateOptions Mandate { get; set; } [JsonProperty("metadata")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("metadata")] -#endif public Dictionary Metadata { get; set; } [JsonProperty("original_source")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("original_source")] -#endif public string OriginalSource { get; set; } [JsonProperty("owner")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("owner")] -#endif public SourceOwnerOptions Owner { get; set; } [JsonProperty("receiver")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("receiver")] -#endif public SourceReceiverOptions Receiver { get; set; } [JsonProperty("redirect")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("redirect")] -#endif public SourceRedirectOptions Redirect { get; set; } [JsonProperty("source_order")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("source_order")] -#endif public SourceSourceOrderOptions SourceOrder { get; set; } [JsonProperty("statement_descriptor")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("statement_descriptor")] -#endif public string StatementDescriptor { get; set; } [JsonProperty("token")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("token")] -#endif public string Token { get; set; } [JsonProperty("type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("type")] -#endif public string Type { get; set; } [JsonProperty("usage")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("usage")] -#endif public string Usage { get; set; } /* @@ -111,65 +76,45 @@ Below we group all Source type specific paramters */ [JsonProperty("acss_debit")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("acss_debit")] -#endif public SourceAcssDebitCreateOptions AcssDebit { get; set; } [JsonProperty("au_becs_debit")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("au_becs_debit")] -#endif public SourceAuBecsDebitCreateOptions AuBecsDebit { get; set; } [JsonProperty("bancontact")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("bancontact")] -#endif public SourceBancontactCreateOptions Bancontact { get; set; } [JsonProperty("card")] [JsonConverter(typeof(AnyOfConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("card")] [STJS.JsonConverter(typeof(STJAnyOfConverter))] -#endif public AnyOf Card { get; set; } [JsonProperty("ideal")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("ideal")] -#endif public SourceIdealCreateOptions Ideal { get; set; } [JsonProperty("klarna")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("klarna")] -#endif public SourceKlarnaCreateOptions Klarna { get; set; } [JsonProperty("sepa_debit")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("sepa_debit")] -#endif public SourceSepaDebitCreateOptions SepaDebit { get; set; } [JsonProperty("sofort")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("sofort")] -#endif public SourceSofortCreateOptions Sofort { get; set; } [JsonProperty("three_d_secure")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("three_d_secure")] -#endif public SourceThreeDSecureCreateOptions ThreeDSecure { get; set; } [JsonProperty("wechat")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("wechat")] -#endif public SourceWechatCreateOptions Wechat { get; set; } } } diff --git a/src/Stripe.net/Services/Sources/SourceIdealCreateOptions.cs b/src/Stripe.net/Services/Sources/SourceIdealCreateOptions.cs index 5d6898d78b..1c4b7f679f 100644 --- a/src/Stripe.net/Services/Sources/SourceIdealCreateOptions.cs +++ b/src/Stripe.net/Services/Sources/SourceIdealCreateOptions.cs @@ -1,16 +1,12 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SourceIdealCreateOptions : INestedOptions { [JsonProperty("bank")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("bank")] -#endif public string Bank { get; set; } } } diff --git a/src/Stripe.net/Services/Sources/SourceKlarnaCreateOptions.cs b/src/Stripe.net/Services/Sources/SourceKlarnaCreateOptions.cs index 0e30bd7af4..369c81b5d7 100644 --- a/src/Stripe.net/Services/Sources/SourceKlarnaCreateOptions.cs +++ b/src/Stripe.net/Services/Sources/SourceKlarnaCreateOptions.cs @@ -1,172 +1,116 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SourceKlarnaCreateOptions : INestedOptions { [JsonProperty("background_image_url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("background_image_url")] -#endif public string BackgroundImageUrl { get; set; } [JsonProperty("client_token")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("client_token")] -#endif public string ClientToken { get; set; } [JsonProperty("first_name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("first_name")] -#endif public string FirstName { get; set; } [JsonProperty("last_name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("last_name")] -#endif public string LastName { get; set; } [JsonProperty("locale")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("locale")] -#endif public string Locale { get; set; } [JsonProperty("logo_url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("logo_url")] -#endif public string LogoUrl { get; set; } [JsonProperty("page_title")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("page_title")] -#endif public string PageTitle { get; set; } [JsonProperty("pay_later_asset_urls_descriptive")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("pay_later_asset_urls_descriptive")] -#endif public string PayLaterAssetUrlsDescriptive { get; set; } [JsonProperty("pay_later_asset_urls_standard")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("pay_later_asset_urls_standard")] -#endif public string PayLaterAssetUrlsStandard { get; set; } [JsonProperty("pay_later_name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("pay_later_name")] -#endif public string PayLaterName { get; set; } [JsonProperty("pay_later_redirect_url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("pay_later_redirect_url")] -#endif public string PayLaterRedirectUrl { get; set; } [JsonProperty("pay_now_asset_urls_descriptive")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("pay_now_asset_urls_descriptive")] -#endif public string PayNowAssetUrlsDescriptive { get; set; } [JsonProperty("pay_now_asset_urls_standard")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("pay_now_asset_urls_standard")] -#endif public string PayNowAssetUrlsStandard { get; set; } [JsonProperty("pay_now_name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("pay_now_name")] -#endif public string PayNowName { get; set; } [JsonProperty("pay_now_redirect_url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("pay_now_redirect_url")] -#endif public string PayNowRedirectUrl { get; set; } [JsonProperty("pay_over_time_asset_urls_descriptive")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("pay_over_time_asset_urls_descriptive")] -#endif public string PayOverTimeAssetUrlsDescriptive { get; set; } [JsonProperty("pay_over_time_asset_urls_standard")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("pay_over_time_asset_urls_standard")] -#endif public string PayOverTimeAssetUrlsStandard { get; set; } [JsonProperty("pay_over_time_name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("pay_over_time_name")] -#endif public string PayOverTimeName { get; set; } [JsonProperty("pay_over_time_redirect_url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("pay_over_time_redirect_url")] -#endif public string PayOverTimeRedirectUrl { get; set; } [JsonProperty("payment_method_categories")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("payment_method_categories")] -#endif public string PaymentMethodCategories { get; set; } [JsonProperty("product")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("product")] -#endif public string Product { get; set; } [JsonProperty("purchase_country")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("purchase_country")] -#endif public string PurchaseCountry { get; set; } [JsonProperty("purchase_type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("purchase_type")] -#endif public string PurchaseType { get; set; } [JsonProperty("redirect_url")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("redirect_url")] -#endif public string RedirectUrl { get; set; } [JsonProperty("shipping_delay")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("shipping_delay")] -#endif public long? ShippingDelay { get; set; } [JsonProperty("shipping_first_name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("shipping_first_name")] -#endif public string ShippingFirstName { get; set; } [JsonProperty("shipping_last_name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("shipping_last_name")] -#endif public string ShippingLastName { get; set; } } } diff --git a/src/Stripe.net/Services/Sources/SourceListOptions.cs b/src/Stripe.net/Services/Sources/SourceListOptions.cs index 3ba4c1afa4..11b4829888 100644 --- a/src/Stripe.net/Services/Sources/SourceListOptions.cs +++ b/src/Stripe.net/Services/Sources/SourceListOptions.cs @@ -1,26 +1,18 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using Stripe.Infrastructure; using STJS = System.Text.Json.Serialization; -#endif -#if NET6_0_OR_GREATER - [STJS.JsonConverter(typeof(STJMemberSerializationOptIn))] -#endif + [STJS.JsonConverter(typeof(STJStripeOptionsConverter))] public class SourceListOptions : ListOptions { [JsonProperty("object")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("object")] -#endif internal string Object => "source"; [JsonProperty("type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("type")] -#endif public string Type { get; set; } } } diff --git a/src/Stripe.net/Services/Sources/SourceSepaDebitCreateOptions.cs b/src/Stripe.net/Services/Sources/SourceSepaDebitCreateOptions.cs index 5b280e3a04..80a538d046 100644 --- a/src/Stripe.net/Services/Sources/SourceSepaDebitCreateOptions.cs +++ b/src/Stripe.net/Services/Sources/SourceSepaDebitCreateOptions.cs @@ -1,22 +1,16 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SourceSepaDebitCreateOptions : INestedOptions { [JsonProperty("iban")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("iban")] -#endif public string Iban { get; set; } [JsonProperty("ideal")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("ideal")] -#endif public string Ideal { get; set; } } } diff --git a/src/Stripe.net/Services/Sources/SourceSofortCreateOptions.cs b/src/Stripe.net/Services/Sources/SourceSofortCreateOptions.cs index c20b27f3a7..bea978bd85 100644 --- a/src/Stripe.net/Services/Sources/SourceSofortCreateOptions.cs +++ b/src/Stripe.net/Services/Sources/SourceSofortCreateOptions.cs @@ -1,16 +1,12 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SourceSofortCreateOptions : INestedOptions { [JsonProperty("country")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("country")] -#endif public string Country { get; set; } } } diff --git a/src/Stripe.net/Services/Sources/SourceThreeDSecureCreateOptions.cs b/src/Stripe.net/Services/Sources/SourceThreeDSecureCreateOptions.cs index fc752902b0..db4cd0cf3f 100644 --- a/src/Stripe.net/Services/Sources/SourceThreeDSecureCreateOptions.cs +++ b/src/Stripe.net/Services/Sources/SourceThreeDSecureCreateOptions.cs @@ -1,22 +1,16 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SourceThreeDSecureCreateOptions : INestedOptions { [JsonProperty("customer")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("customer")] -#endif public string Customer { get; set; } [JsonProperty("card")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("card")] -#endif public string Card { get; set; } } } diff --git a/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionScheduleInvoiceSettingsOptions.cs b/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionScheduleInvoiceSettingsOptions.cs index 269422cbf5..ae55ff3ac3 100644 --- a/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionScheduleInvoiceSettingsOptions.cs +++ b/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionScheduleInvoiceSettingsOptions.cs @@ -1,16 +1,12 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SubscriptionScheduleInvoiceSettingsOptions : INestedOptions { [JsonProperty("days_until_due")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("days_until_due")] -#endif public long? DaysUntilDue { get; set; } } } diff --git a/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionSchedulePhasePlanBillingThresholdsOptions.cs b/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionSchedulePhasePlanBillingThresholdsOptions.cs index ef436e07be..e341fb16ac 100644 --- a/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionSchedulePhasePlanBillingThresholdsOptions.cs +++ b/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionSchedulePhasePlanBillingThresholdsOptions.cs @@ -1,16 +1,12 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SubscriptionSchedulePhasePlanBillingThresholdsOptions : INestedOptions { [JsonProperty("usage_gte")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("usage_gte")] -#endif public long? UsageGte { get; set; } } } diff --git a/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionSchedulePhasePlanPriceDataOptions.cs b/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionSchedulePhasePlanPriceDataOptions.cs index c1b2634958..360aa01db5 100644 --- a/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionSchedulePhasePlanPriceDataOptions.cs +++ b/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionSchedulePhasePlanPriceDataOptions.cs @@ -1,40 +1,31 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER + using Stripe.Infrastructure; using STJS = System.Text.Json.Serialization; -#endif public class SubscriptionSchedulePhasePlanPriceDataOptions : INestedOptions { [JsonProperty("currency")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("currency")] -#endif public string Currency { get; set; } [JsonProperty("product")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("product")] -#endif public string Product { get; set; } [JsonProperty("recurring")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("recurring")] -#endif public SubscriptionSchedulePhasePlanPriceDataRecurringOptions Recurring { get; set; } [JsonProperty("unit_amount")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("unit_amount")] -#endif public long? UnitAmount { get; set; } + [JsonConverter(typeof(DecimalStringConverter))] [JsonProperty("unit_amount_decimal")] -#if NET6_0_OR_GREATER + [STJS.JsonNumberHandling(STJS.JsonNumberHandling.AllowReadingFromString | STJS.JsonNumberHandling.WriteAsString)] [STJS.JsonPropertyName("unit_amount_decimal")] -#endif public decimal? UnitAmountDecimal { get; set; } } } diff --git a/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionSchedulePhasePlanPriceDataRecurringOptions.cs b/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionSchedulePhasePlanPriceDataRecurringOptions.cs index bf32bca885..9ff0bda296 100644 --- a/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionSchedulePhasePlanPriceDataRecurringOptions.cs +++ b/src/Stripe.net/Services/SubscriptionSchedules/SubscriptionSchedulePhasePlanPriceDataRecurringOptions.cs @@ -1,9 +1,7 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SubscriptionSchedulePhasePlanPriceDataRecurringOptions : INestedOptions { @@ -13,9 +11,7 @@ public class SubscriptionSchedulePhasePlanPriceDataRecurringOptions : INestedOpt /// One of: day, month, week, or year. /// [JsonProperty("interval")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("interval")] -#endif public string Interval { get; set; } /// @@ -24,9 +20,7 @@ public class SubscriptionSchedulePhasePlanPriceDataRecurringOptions : INestedOpt /// year interval allowed (1 year, 12 months, or 52 weeks). /// [JsonProperty("interval_count")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("interval_count")] -#endif public long? IntervalCount { get; set; } } } diff --git a/src/Stripe.net/Services/TaxRates/TaxRatePercentageRangeOptions.cs b/src/Stripe.net/Services/TaxRates/TaxRatePercentageRangeOptions.cs index 3c55eb75de..18257e4656 100644 --- a/src/Stripe.net/Services/TaxRates/TaxRatePercentageRangeOptions.cs +++ b/src/Stripe.net/Services/TaxRates/TaxRatePercentageRangeOptions.cs @@ -1,39 +1,28 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; public class TaxRatePercentageRangeOptions : INestedOptions { [JsonProperty("gt")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("gt")] -#endif [AllowNameMismatch] public decimal? GreaterThan { get; set; } [JsonProperty("gte")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("gte")] -#endif [AllowNameMismatch] public decimal? GreaterThanOrEqual { get; set; } [JsonProperty("lt")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("lt")] -#endif [AllowNameMismatch] public decimal? LessThan { get; set; } [JsonProperty("lte")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("lte")] -#endif [AllowNameMismatch] public decimal? LessThanOrEqual { get; set; } } diff --git a/src/Stripe.net/Services/_base/BaseOptions.cs b/src/Stripe.net/Services/_base/BaseOptions.cs index 6569f983a1..05e50dce59 100644 --- a/src/Stripe.net/Services/_base/BaseOptions.cs +++ b/src/Stripe.net/Services/_base/BaseOptions.cs @@ -3,31 +3,27 @@ namespace Stripe using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER + using Stripe.Infrastructure; using STJS = System.Text.Json.Serialization; -#endif /// /// Base class for Stripe options classes, i.e. classes representing parameters for Stripe /// API requests. /// [JsonObject(MemberSerialization.OptIn)] + [STJS.JsonConverter(typeof(STJStripeOptionsConverter))] public class BaseOptions : INestedOptions { /// Specifies which fields in the response should be expanded. [JsonProperty("expand", NullValueHandling = NullValueHandling.Ignore)] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("expand")] [STJS.JsonIgnore(Condition = STJS.JsonIgnoreCondition.WhenWritingNull)] -#endif public List Expand { get; set; } /// Dictionary containing extra request parameters. [JsonExtensionData] -#if NET6_0_OR_GREATER [STJS.JsonExtensionData] -#endif public IDictionary ExtraParams { get; set; } = new Dictionary(); diff --git a/src/Stripe.net/Services/_base/ListOptions.cs b/src/Stripe.net/Services/_base/ListOptions.cs index 42e8c165e0..fc9bbb0d83 100644 --- a/src/Stripe.net/Services/_base/ListOptions.cs +++ b/src/Stripe.net/Services/_base/ListOptions.cs @@ -2,9 +2,7 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class ListOptions : BaseOptions { @@ -12,9 +10,7 @@ public class ListOptions : BaseOptions /// A limit on the number of objects to be returned, between 1 and 100. /// [JsonProperty("limit")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("limit")] -#endif public long? Limit { get; set; } /// @@ -24,9 +20,7 @@ public class ListOptions : BaseOptions /// starting_after=obj_foo in order to fetch the next page of the list. /// [JsonProperty("starting_after")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("starting_after")] -#endif public string StartingAfter { get; set; } /// @@ -36,9 +30,7 @@ public class ListOptions : BaseOptions /// ending_before=obj_bar in order to fetch the previous page of the list. /// [JsonProperty("ending_before")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("ending_before")] -#endif public string EndingBefore { get; set; } } } diff --git a/src/Stripe.net/Services/_base/SearchOptions.cs b/src/Stripe.net/Services/_base/SearchOptions.cs index a2c815fe7b..94a7789338 100644 --- a/src/Stripe.net/Services/_base/SearchOptions.cs +++ b/src/Stripe.net/Services/_base/SearchOptions.cs @@ -1,9 +1,7 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class SearchOptions : BaseOptions { @@ -11,21 +9,15 @@ public class SearchOptions : BaseOptions /// A limit on the number of objects to be returned, between 1 and 100. /// [JsonProperty("limit")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("limit")] -#endif public long? Limit { get; set; } [JsonProperty("page")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("page")] -#endif public string Page { get; set; } [JsonProperty("query")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("query")] -#endif public string Query { get; set; } } } diff --git a/src/Stripe.net/Services/_base/StringEnum.cs b/src/Stripe.net/Services/_base/StringEnum.cs index e9379345cc..71c43a40a7 100644 --- a/src/Stripe.net/Services/_base/StringEnum.cs +++ b/src/Stripe.net/Services/_base/StringEnum.cs @@ -1,5 +1,7 @@ namespace Stripe { + using System.Text.Json.Serialization; + /// /// Abstract base class for string enum parameters. /// @@ -34,6 +36,7 @@ protected StringEnum(string value) /// Gets or sets the serialized value. /// The serialized value. + [JsonPropertyName("Value")] public string Value { get; protected set; } /// Returns the serialized value. diff --git a/src/Stripe.net/Services/_base/V2/ListOptions.cs b/src/Stripe.net/Services/_base/V2/ListOptions.cs index f63843a2e1..038a970944 100644 --- a/src/Stripe.net/Services/_base/V2/ListOptions.cs +++ b/src/Stripe.net/Services/_base/V2/ListOptions.cs @@ -1,9 +1,7 @@ namespace Stripe.V2 { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class ListOptions : BaseOptions { @@ -11,9 +9,7 @@ public class ListOptions : BaseOptions /// A limit on the number of objects to be returned, between 1 and 100. /// [JsonProperty("limit")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("limit")] -#endif public long? Limit { get; set; } } } diff --git a/src/Stripe.net/Services/_common/AddressJapanOptions.cs b/src/Stripe.net/Services/_common/AddressJapanOptions.cs index d80f71dbbf..e369705865 100644 --- a/src/Stripe.net/Services/_common/AddressJapanOptions.cs +++ b/src/Stripe.net/Services/_common/AddressJapanOptions.cs @@ -1,16 +1,12 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class AddressJapanOptions : AddressOptions { [JsonProperty("town")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("town")] -#endif public string Town { get; set; } } } diff --git a/src/Stripe.net/Services/_common/AddressOptions.cs b/src/Stripe.net/Services/_common/AddressOptions.cs index da0693a3b9..1de8cf7fc6 100644 --- a/src/Stripe.net/Services/_common/AddressOptions.cs +++ b/src/Stripe.net/Services/_common/AddressOptions.cs @@ -1,46 +1,32 @@ namespace Stripe { using Newtonsoft.Json; -#if NET6_0_OR_GREATER using STJS = System.Text.Json.Serialization; -#endif public class AddressOptions : INestedOptions { [JsonProperty("city")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("city")] -#endif public string City { get; set; } [JsonProperty("country")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("country")] -#endif public string Country { get; set; } [JsonProperty("line1")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("line1")] -#endif public string Line1 { get; set; } [JsonProperty("line2")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("line2")] -#endif public string Line2 { get; set; } [JsonProperty("postal_code")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("postal_code")] -#endif public string PostalCode { get; set; } [JsonProperty("state")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("state")] -#endif public string State { get; set; } } } diff --git a/src/Stripe.net/Services/_common/DateRangeOptions.cs b/src/Stripe.net/Services/_common/DateRangeOptions.cs index ad38065039..d9e42819f9 100644 --- a/src/Stripe.net/Services/_common/DateRangeOptions.cs +++ b/src/Stripe.net/Services/_common/DateRangeOptions.cs @@ -2,47 +2,36 @@ namespace Stripe { using System; using Newtonsoft.Json; -#if NET6_0_OR_GREATER - using STJS = System.Text.Json.Serialization; -#endif - using Stripe.Infrastructure; + using STJS = System.Text.Json.Serialization; public class DateRangeOptions : INestedOptions { [JsonProperty("gt")] [JsonConverter(typeof(UnixDateTimeConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("gt")] [STJS.JsonConverter(typeof(STJUnixDateTimeConverter))] -#endif [AllowNameMismatch] public DateTime? GreaterThan { get; set; } [JsonProperty("gte")] [JsonConverter(typeof(UnixDateTimeConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("gte")] [STJS.JsonConverter(typeof(STJUnixDateTimeConverter))] -#endif [AllowNameMismatch] public DateTime? GreaterThanOrEqual { get; set; } [JsonProperty("lt")] [JsonConverter(typeof(UnixDateTimeConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("lt")] [STJS.JsonConverter(typeof(STJUnixDateTimeConverter))] -#endif [AllowNameMismatch] public DateTime? LessThan { get; set; } [JsonProperty("lte")] [JsonConverter(typeof(UnixDateTimeConverter))] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("lte")] [STJS.JsonConverter(typeof(STJUnixDateTimeConverter))] -#endif [AllowNameMismatch] public DateTime? LessThanOrEqual { get; set; } } diff --git a/src/Stripe.net/Services/_common/MultipartFileContent.cs b/src/Stripe.net/Services/_common/MultipartFileContent.cs index 17f46b4180..67823a07a9 100644 --- a/src/Stripe.net/Services/_common/MultipartFileContent.cs +++ b/src/Stripe.net/Services/_common/MultipartFileContent.cs @@ -1,6 +1,7 @@ namespace Stripe { using System.IO; + using System.Text.Json.Serialization; /// /// Represents Data and optional Name and Type that will be encoded as multipart form @@ -14,18 +15,21 @@ public class MultipartFileContent /// the name and type from the file name and extension. If this is not /// a FileStream set Name and Type to configure the file upload. /// + [JsonPropertyName("Data")] public Stream Data { get; set; } /// /// The optional name to send with this file data. Uses the file name if omitted /// and Data is a FileStream. /// + [JsonPropertyName("Name")] public string Name { get; set; } /// /// The optional mime type to use when sending file data. Uses the type that /// matches the file extension from Name (or the file name from Data) if omitted. /// + [JsonPropertyName("Type")] public string Type { get; set; } } } diff --git a/src/Stripe.net/Services/_common/RequestOptions.cs b/src/Stripe.net/Services/_common/RequestOptions.cs index 2d22a01e7a..2faeaf6377 100644 --- a/src/Stripe.net/Services/_common/RequestOptions.cs +++ b/src/Stripe.net/Services/_common/RequestOptions.cs @@ -27,6 +27,9 @@ public class RequestOptions /// Gets or sets the value or Stripe-Context request header. public string StripeContext { get; set; } + /// Gets or sets the value of the Stripe-Request-Trigger request header. + public string StripeRequestTrigger { get; set; } + /// Gets the base URL for the request. /// /// This is an internal property. It is set by services or individual request methods when diff --git a/src/Stripe.net/Services/_refactor/SourceBankAccount.cs b/src/Stripe.net/Services/_refactor/SourceBankAccount.cs index 7b72157cd4..ff0355e79f 100644 --- a/src/Stripe.net/Services/_refactor/SourceBankAccount.cs +++ b/src/Stripe.net/Services/_refactor/SourceBankAccount.cs @@ -2,69 +2,47 @@ namespace Stripe { using System.Collections.Generic; using Newtonsoft.Json; -#if NET6_0_OR_GREATER using Stripe.Infrastructure; using STJS = System.Text.Json.Serialization; -#endif -#if NET6_0_OR_GREATER - [STJS.JsonConverter(typeof(STJMemberSerializationOptIn))] -#endif + [STJS.JsonConverter(typeof(STJStripeOptionsConverter))] public class SourceBankAccount : INestedOptions, IHasMetadata { [JsonProperty("object")] -#if NET6_0_OR_GREATER [STJS.JsonInclude] [STJS.JsonPropertyName("object")] -#endif internal string Object => "bank_account"; [JsonProperty("account_holder_name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("account_holder_name")] -#endif public string AccountHolderName { get; set; } [JsonProperty("account_holder_type")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("account_holder_type")] -#endif public string AccountHolderType { get; set; } [JsonProperty("account_number")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("account_number")] -#endif public string AccountNumber { get; set; } [JsonProperty("bank_name")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("bank_name")] -#endif public string BankName { get; set; } [JsonProperty("country")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("country")] -#endif public string Country { get; set; } [JsonProperty("currency")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("currency")] -#endif public string Currency { get; set; } [JsonProperty("metadata")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("metadata")] -#endif public Dictionary Metadata { get; set; } [JsonProperty("routing_number")] -#if NET6_0_OR_GREATER [STJS.JsonPropertyName("routing_number")] -#endif public string RoutingNumber { get; set; } } } diff --git a/src/Stripe.net/Stripe.net.csproj b/src/Stripe.net/Stripe.net.csproj index 7b8243cb9a..6fb67ee9ea 100644 --- a/src/Stripe.net/Stripe.net.csproj +++ b/src/Stripe.net/Stripe.net.csproj @@ -2,7 +2,7 @@ Stripe.net is a sync/async client and portable class library for the Stripe API, supporting .NET Standard 2.0+, .NET Core 5+, and .NET Framework 4.6.2+. (Official Library) - 50.3.0 + 50.4.1 8 Stripe, Jayme Davis