Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit 35645ce

Browse files
committed
Add support for writing dictionaries in custom complex type strategy
1 parent de1602e commit 35645ce

File tree

4 files changed

+210
-20
lines changed

4 files changed

+210
-20
lines changed

src/ServiceStack.Text/Common/WriteType.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
using System;
1414
using System.Collections;
15+
using System.Collections.Generic;
1516
using System.IO;
1617
using System.Linq;
1718
using System.Reflection;
@@ -576,11 +577,14 @@ public static void WriteQueryString(TextWriter writer, object value)
576577
&& !propertyType.IsValueType()
577578
&& propertyType.HasInterface(typeof(IEnumerable));
578579

579-
if (QueryStringSerializer.ComplexTypeStrategy != null
580-
&& !isEnumerable && (propertyType.IsUserType() || propertyType.IsInterface()))
580+
if (QueryStringSerializer.ComplexTypeStrategy != null)
581581
{
582-
if (QueryStringSerializer.ComplexTypeStrategy(writer, propertyWriter.PropertyName, propertyValue))
583-
continue;
582+
var nonEnumerableUserType = !isEnumerable && (propertyType.IsUserType() || propertyType.IsInterface());
583+
if (nonEnumerableUserType || propertyType.IsOrHasGenericInterfaceTypeOf(typeof(IDictionary<,>)))
584+
{
585+
if (QueryStringSerializer.ComplexTypeStrategy(writer, propertyWriter.PropertyName, propertyValue))
586+
continue;
587+
}
584588
}
585589

586590
Serializer.WritePropertyName(writer, propertyWriter.PropertyName);

src/ServiceStack.Text/QueryStringSerializer.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using System.Threading;
2222
using ServiceStack.Text;
2323
using ServiceStack.Text.Common;
24+
using ServiceStack.Text.Json;
2425
using ServiceStack.Text.Jsv;
2526

2627
namespace ServiceStack
@@ -235,6 +236,31 @@ public static class QueryStringStrategy
235236

236237
public static bool FormUrlEncoded(TextWriter writer, string propertyName, object obj)
237238
{
239+
var map = obj as IDictionary;
240+
if (map != null)
241+
{
242+
foreach (var key in map.Keys)
243+
{
244+
var value = map[key];
245+
writer.Write(propertyName);
246+
writer.Write('[');
247+
writer.Write(key.ToString());
248+
writer.Write("]=");
249+
250+
if (value == null)
251+
{
252+
writer.Write(JsonUtils.Null);
253+
}
254+
else
255+
{
256+
var writeFn = JsvWriter.GetWriteFn(value.GetType());
257+
writeFn(writer, value);
258+
}
259+
}
260+
261+
return true;
262+
}
263+
238264
var typeConfig = typeConfigCache.GetOrAdd(obj.GetType(), t =>
239265
{
240266
var genericType = typeof(PropertyTypeConfig<>).MakeGenericType(t);

tests/ServiceStack.Text.Tests/UseCases/StripeGateway.cs

Lines changed: 159 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
using System.Collections.Generic;
66
using System.Net;
77
using System.Runtime.Serialization;
8+
using System.Text;
89
using System.Threading.Tasks;
910
using ServiceStack.Stripe.Types;
1011
using ServiceStack.Text;
1112

1213
namespace ServiceStack.Stripe
1314
{
14-
/* Charges
15+
/* Charges
1516
* https://stripe.com/docs/api/curl#charges
1617
*/
1718
[Route("/charges")]
@@ -83,7 +84,7 @@ public string ToUrl(string absoluteUrl)
8384
}
8485
}
8586

86-
/* Customers
87+
/* Customers
8788
* https://stripe.com/docs/api/curl#customers
8889
*/
8990
[Route("/customers")]
@@ -97,6 +98,9 @@ public class CreateStripeCustomer : IPost, IReturn<StripeCustomer>
9798
public string Plan { get; set; }
9899
public int? Quantity { get; set; }
99100
public DateTime? TrialEnd { get; set; }
101+
public Dictionary<string, string> Metadata { get; set; }
102+
public string Currency { get; set; }
103+
public string BusinessVatId { get; set; }
100104
}
101105

102106
[Route("/customers")]
@@ -110,6 +114,9 @@ public class CreateStripeCustomerWithToken : IPost, IReturn<StripeCustomer>
110114
public string Plan { get; set; }
111115
public int? Quantity { get; set; }
112116
public DateTime? TrialEnd { get; set; }
117+
public Dictionary<string, string> Metadata { get; set; }
118+
public string Currency { get; set; }
119+
public string BusinessVatId { get; set; }
113120
}
114121

115122
[Route("/customers/{Id}")]
@@ -130,6 +137,9 @@ public class UpdateStripeCustomer : IPost, IReturn<StripeCustomer>
130137
public string Description { get; set; }
131138
public string Email { get; set; }
132139
public string Source { get; set; }
140+
public Dictionary<string, string> Metadata { get; set; }
141+
public string Currency { get; set; }
142+
public string BusinessVatId { get; set; }
133143
}
134144

135145
[Route("/customers/{Id}")]
@@ -376,12 +386,22 @@ public class PayStripeInvoice : IPost, IReturn<StripeInvoice>
376386
}
377387

378388
[Route("/invoices")]
379-
public class GetStripeInvoices : IGet, IReturn<StripeCollection<StripeInvoice>>
389+
public class GetStripeInvoices : IGet, IReturn<StripeCollection<StripeInvoice>>, IUrlFilter
380390
{
381391
public string Customer { get; set; }
382392
public DateTime? Date { get; set; }
383393
public int? Count { get; set; }
384394
public int? Offset { get; set; }
395+
396+
[IgnoreDataMember]
397+
public StripeDateOptions DateOptions { get; set; }
398+
399+
public string ToUrl(string absoluteUrl)
400+
{
401+
return Date != null || DateOptions == null
402+
? absoluteUrl
403+
: absoluteUrl.AppendOptions("date", DateOptions);
404+
}
385405
}
386406

387407
[Route("/invoices/upcoming")]
@@ -408,12 +428,11 @@ public class StripeToken : StripeId
408428
public StripeCard Card { get; set; }
409429
}
410430

411-
/*
412-
Accounts
431+
/*
432+
Accounts
413433
*/
414-
415434
[Route("/accounts")]
416-
public class CreateStripeAccount : IPost, IReturn<StripeAccount>
435+
public class CreateStripeAccount : IPost, IReturn<CreateStripeAccountResponse>
417436
{
418437
public string Country { get; set; }
419438
public bool Managed { get; set; }
@@ -422,6 +441,11 @@ public class CreateStripeAccount : IPost, IReturn<StripeAccount>
422441
public StripeLegalEntity LegalEntity { get; set; }
423442
}
424443

444+
public class CreateStripeAccountResponse : StripeAccount
445+
{
446+
public Dictionary<string, string> Keys { get; set; }
447+
}
448+
425449
public class StripeTosAcceptance
426450
{
427451
public DateTime Date { get; set; }
@@ -431,18 +455,74 @@ public class StripeTosAcceptance
431455

432456
public class StripeLegalEntity
433457
{
434-
public StripeDob Dob { get; set; }
458+
public StripeOwner[] AdditionalOwners { get; set; }
459+
public StripeAddress Address { get; set; }
460+
public string BusinessName { get; set; }
461+
public bool? BusinessTaxIdProvided { get; set; }
462+
public StripeDate Dob { get; set; }
463+
public string FirstName { get; set; }
464+
public string LastName { get; set; }
465+
public StripeAddress PersonalAddress { get; set; }
466+
public bool? PersonalIdNumberProvided { get; set; }
467+
public bool? SsnLast4Provided { get; set; }
468+
public string Type { get; set; }
469+
public StripeVerificationBusiness Verification { get; set; }
435470
}
436471

437472
public class StripeAccount : StripeId
438473
{
439-
public Dictionary<string, string> Keys { get; set; }
474+
public string BusinessName { get; set; }
475+
public string BusinessPrimaryColor { get; set; }
476+
public string BusinessUrl { get; set; }
477+
public bool ChargesEnabled { get; set; }
478+
public string Country { get; set; }
479+
public string[] CurrenciesSupported { get; set; }
480+
public bool DebitNegativeBalances { get; set; }
481+
public StripeDeclineCharge DeclineChargeOn { get; set; }
482+
public string DefaultCurrency { get; set; }
483+
public bool DetailsSubmitted { get; set; }
484+
public string DisplayName { get; set; }
485+
public string Email { get; set; }
486+
public StripeLegalEntity LegalEntity { get; set; }
487+
public bool Managed { get; set; }
488+
public string ProductDescription { get; set; }
489+
public string StatementDescriptor { get; set; }
490+
public string SupportEmail { get; set; }
491+
public string SupportPhone { get; set; }
492+
public string SupportUrl { get; set; }
493+
public string Timezone { get; set; }
494+
public StripeTosAcceptance TosAcceptance { get; set; }
495+
public StripeVerificationAccount Verification { get; set; }
496+
}
497+
498+
public class StripeDeclineCharge
499+
{
500+
public bool AvsFailure { get; set; }
501+
public bool CvcFailure { get; set; }
502+
}
503+
504+
public class StripeOwner
505+
{
506+
public StripeAddress Address { get; set; }
507+
public StripeDate Dob { get; set; }
508+
public string FirstName { get; set; }
509+
public string LastName { get; set; }
440510
}
441511

442-
public class StripeDob
512+
public class StripeAddress
443513
{
444-
public StripeDob() {}
445-
public StripeDob(int year, int month, int day)
514+
public string City { get; set; }
515+
public string Country { get; set; }
516+
public string Line1 { get; set; }
517+
public string Line2 { get; set; }
518+
public string PostalCode { get; set; }
519+
public string State { get; set; }
520+
}
521+
522+
public class StripeDate
523+
{
524+
public StripeDate() { }
525+
public StripeDate(int year, int month, int day)
446526
{
447527
Year = year;
448528
Month = month;
@@ -454,6 +534,30 @@ public StripeDob(int year, int month, int day)
454534
public int Day { get; set; }
455535
}
456536

537+
public class StripeVerificationBusiness
538+
{
539+
public string Details { get; set; }
540+
public string DetailsCode { get; set; }
541+
public string Document { get; set; }
542+
public string Status { get; set; }
543+
}
544+
545+
public class StripeTransferSchedule
546+
{
547+
public int DelayDays { get; set; }
548+
public string Interval { get; set; }
549+
public int MonthlyAnchor { get; set; }
550+
public string WeeklyAnchor { get; set; }
551+
public bool TransfersEnabled { get; set; }
552+
}
553+
554+
public class StripeVerificationAccount
555+
{
556+
public string DisabledReason { get; set; }
557+
public DateTime? DueBy { get; set; }
558+
public string[] FieldsNeeded { get; set; }
559+
}
560+
457561

458562
public class StripeGateway : IRestGateway
459563
{
@@ -637,12 +741,14 @@ private static string GetMethod<T>(IReturn<T> request)
637741

638742
public T Send<T>(IReturn<T> request)
639743
{
640-
return Send(request, GetMethod(request), sendRequestBody: false);
744+
var method = GetMethod(request);
745+
return Send(request, method, sendRequestBody: method == HttpMethods.Post || method == HttpMethods.Put);
641746
}
642747

643748
public Task<T> SendAsync<T>(IReturn<T> request)
644749
{
645-
return SendAsync(request, GetMethod(request), sendRequestBody: false);
750+
var method = GetMethod(request);
751+
return SendAsync(request, method, sendRequestBody: method == HttpMethods.Post || method == HttpMethods.Put);
646752
}
647753

648754
public T Get<T>(IReturn<T> request)
@@ -695,6 +801,42 @@ public Task<T> DeleteAsync<T>(IReturn<T> request)
695801
return SendAsync(request, HttpMethods.Delete, sendRequestBody: false);
696802
}
697803
}
804+
805+
public class StripeDateOptions
806+
{
807+
public DateTime? After { get; set; }
808+
public DateTime? OnOrAfter { get; set; }
809+
public DateTime? Before { get; set; }
810+
public DateTime? OnOrBefore { get; set; }
811+
}
812+
813+
internal static class UrlExtensions
814+
{
815+
public static string AppendOptions(this string url, string name, StripeDateOptions options)
816+
{
817+
var sb = new StringBuilder();
818+
var map = new Dictionary<string, DateTime?>
819+
{
820+
{ "gt", options.After },
821+
{ "gte", options.OnOrAfter },
822+
{ "lt", options.Before },
823+
{ "lte", options.OnOrBefore },
824+
};
825+
826+
foreach (var entry in map)
827+
{
828+
if (entry.Value == null)
829+
continue;
830+
831+
url = url.AddQueryParam(
832+
"{0}[{1}]".Fmt(name, entry.Key),
833+
entry.Value.Value.ToUnixTime());
834+
}
835+
836+
return url;
837+
}
838+
}
839+
698840
}
699841

700842
namespace ServiceStack.Stripe.Types
@@ -877,6 +1019,8 @@ public class StripeCustomer : StripeId
8771019

8781020
public bool Deleted { get; set; }
8791021
public string DefaultSource { get; set; }
1022+
public string Currency { get; set; }
1023+
public string BusinessVatId { get; set; }
8801024
}
8811025

8821026
public class GetAllStripeCustomers
@@ -1196,4 +1340,4 @@ public static class Currencies
11961340
public const string YemeniRial = "YER";
11971341
public const string SouthAfricanRand = "ZAR";
11981342
}
1199-
}
1343+
}

0 commit comments

Comments
 (0)