@@ -43,8 +43,6 @@ public class DocuSignClient
43
43
public const string Production_REST_BasePath = "https://www.docusign.net/restapi" ;
44
44
// Sandbox/Demo base path
45
45
public const string Demo_REST_BasePath = "https://demo.docusign.net/restapi" ;
46
- // Stage base path
47
- public const string Stage_REST_BasePath = "https://stage.docusign.net/restapi" ;
48
46
49
47
protected string basePath = Demo_REST_BasePath ;
50
48
@@ -317,6 +315,47 @@ public string ParameterToString(object obj)
317
315
return Convert . ToString ( obj ) ;
318
316
}
319
317
318
+ /// <summary>
319
+ /// Parses a CSV-formatted string and converts it into a list of dictionaries,
320
+ /// where each dictionary represents a record with column headers as keys.
321
+ /// </summary>
322
+ /// <param name="content">The CSV-formatted string to be deserialized.</param>
323
+ /// <returns>A list of dictionaries, each containing key-value pairs of column headers and their corresponding values.</returns>
324
+ private object DeserializeStringToCsv ( string content )
325
+ {
326
+ var records = new List < Dictionary < string , object > > ( ) ;
327
+
328
+ // Split the CSV string into lines
329
+ var lines = content . Split ( new [ ] { '\n ' } , StringSplitOptions . RemoveEmptyEntries ) ;
330
+
331
+ // Check if there are any lines
332
+ if ( lines . Length > 0 )
333
+ {
334
+ // Read the header line
335
+ string [ ] headers = lines [ 0 ] . Split ( ',' ) ;
336
+
337
+ // Read the rest of the lines
338
+ for ( int i = 1 ; i < lines . Length ; i ++ )
339
+ {
340
+ string [ ] values = lines [ i ] . Split ( ',' ) ;
341
+ var record = new Dictionary < string , object > ( ) ;
342
+
343
+ for ( int j = 0 ; j < headers . Length ; j ++ )
344
+ {
345
+ // Ensure we don't exceed the number of values
346
+ if ( j < values . Length )
347
+ {
348
+ record [ headers [ j ] ] = values [ j ] ; // Store the value in the dictionary
349
+ }
350
+ }
351
+
352
+ records . Add ( record ) ; // Add the record to the list
353
+ }
354
+ }
355
+
356
+ return records ; // Return the list of records
357
+ }
358
+
320
359
/// <summary>
321
360
/// Deserialize the JSON string into a proper object.
322
361
/// </summary>
@@ -345,6 +384,11 @@ public object Deserialize(DocuSignResponse response, Type type)
345
384
return ConvertType ( response . Content , type ) ;
346
385
}
347
386
387
+ if ( response . ContentType == "text/csv" )
388
+ {
389
+ return DeserializeStringToCsv ( response . Content ) ;
390
+ }
391
+
348
392
// at this point, it must be a model (json)
349
393
try
350
394
{
@@ -724,10 +768,6 @@ public void SetOAuthBasePath(string oauthBaseUri = null)
724
768
{
725
769
this . oAuthBasePath = OAuth . Demo_OAuth_BasePath ;
726
770
}
727
- else if ( baseUri . Host . StartsWith ( "apps-s" ) || baseUri . Host . StartsWith ( "stage" ) )
728
- {
729
- this . oAuthBasePath = OAuth . Stage_OAuth_BasePath ;
730
- }
731
771
else
732
772
{
733
773
this . oAuthBasePath = OAuth . Production_OAuth_BasePath ;
@@ -774,8 +814,14 @@ private static T TryCatchWrapper<T>(Func<T> func)
774
814
/// </returns>
775
815
public OAuth . OAuthToken GenerateAccessToken ( string clientId , string clientSecret , string code )
776
816
{
777
- CancellationTokenSource cts = new CancellationTokenSource ( ) ;
778
- return TryCatchWrapper ( ( ) => GenerateAccessTokenAsync ( clientId , clientSecret , code , cts . Token ) . ConfigureAwait ( false ) . GetAwaiter ( ) . GetResult ( ) ) ;
817
+ using ( var cts = new CancellationTokenSource ( ) )
818
+ {
819
+ return TryCatchWrapper ( ( ) => {
820
+ var task = Task . Run ( async ( ) => await GenerateAccessTokenAsync ( clientId , clientSecret , code , cts . Token ) ) ;
821
+ task . Wait ( ) ;
822
+ return task . Result ;
823
+ } ) ;
824
+ }
779
825
}
780
826
781
827
/// <summary>
@@ -790,7 +836,7 @@ public OAuth.OAuthToken GenerateAccessToken(string clientId, string clientSecret
790
836
/// ApiException if the HTTP call status is different than 2xx.
791
837
/// IOException if there is a problem while parsing the reponse object.
792
838
/// </returns>
793
- public async Task < OAuth . OAuthToken > GenerateAccessTokenAsync ( string clientId , string clientSecret , string code , CancellationToken cancellationToken )
839
+ public async Task < OAuth . OAuthToken > GenerateAccessTokenAsync ( string clientId , string clientSecret , string code , CancellationToken cancellationToken = default )
794
840
{
795
841
if ( string . IsNullOrEmpty ( clientId ) || string . IsNullOrEmpty ( clientSecret ) || string . IsNullOrEmpty ( code ) )
796
842
{
@@ -840,8 +886,14 @@ public OAuth.OAuthToken GenerateAccessToken(string clientId, string clientSecret
840
886
/// <returns>The User Info model.</returns>
841
887
public OAuth . UserInfo GetUserInfo ( string accessToken )
842
888
{
843
- CancellationTokenSource cts = new CancellationTokenSource ( ) ;
844
- return TryCatchWrapper ( ( ) => GetUserInfoAsync ( accessToken , cts . Token ) . ConfigureAwait ( false ) . GetAwaiter ( ) . GetResult ( ) ) ;
889
+ using ( var cts = new CancellationTokenSource ( ) )
890
+ {
891
+ return TryCatchWrapper ( ( ) => {
892
+ var task = Task . Run ( async ( ) => await GetUserInfoAsync ( accessToken , cts . Token ) ) ;
893
+ task . Wait ( ) ;
894
+ return task . Result ;
895
+ } ) ;
896
+ }
845
897
}
846
898
847
899
/// <summary>
@@ -850,7 +902,7 @@ public OAuth.UserInfo GetUserInfo(string accessToken)
850
902
/// <param name="accessToken"></param>
851
903
/// <param name="cancellationToken">A CancellationToken which can be used to propagate notification that operations should be canceled. </param>
852
904
/// <returns>The User Info model.</returns>
853
- public async Task < OAuth . UserInfo > GetUserInfoAsync ( string accessToken , CancellationToken cancellationToken )
905
+ public async Task < OAuth . UserInfo > GetUserInfoAsync ( string accessToken , CancellationToken cancellationToken = default )
854
906
{
855
907
if ( string . IsNullOrEmpty ( accessToken ) )
856
908
{
@@ -913,7 +965,7 @@ protected static RSA CreateRSAKeyFromPem(string key)
913
965
/// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
914
966
/// <param name="userId">Docusign user Id to be impersonated(This is a UUID)</param>
915
967
/// <param name="oauthBasePath"> Docusign OAuth base path
916
- /// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/> <see cref="OAuth.Stage_OAuth_BasePath"/>
968
+ /// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/>
917
969
/// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
918
970
/// </param>
919
971
/// <param name="privateKeyStream">The Stream of the RSA private key</param>
@@ -924,8 +976,14 @@ protected static RSA CreateRSAKeyFromPem(string key)
924
976
/// <returns>The JWT user token</returns>
925
977
public OAuth . OAuthToken RequestJWTUserToken ( string clientId , string userId , string oauthBasePath , Stream privateKeyStream , int expiresInHours , List < string > scopes = null )
926
978
{
927
- CancellationTokenSource cts = new CancellationTokenSource ( ) ;
928
- return TryCatchWrapper ( ( ) => RequestJWTUserTokenAsync ( clientId , userId , oauthBasePath , privateKeyStream , expiresInHours , scopes , cts . Token ) . ConfigureAwait ( false ) . GetAwaiter ( ) . GetResult ( ) ) ;
979
+ using ( var cts = new CancellationTokenSource ( ) )
980
+ {
981
+ return TryCatchWrapper ( ( ) => {
982
+ var task = Task . Run ( async ( ) => await RequestJWTUserTokenAsync ( clientId , userId , oauthBasePath , privateKeyStream , expiresInHours , scopes , cts . Token ) ) ;
983
+ task . Wait ( ) ;
984
+ return task . Result ;
985
+ } ) ;
986
+ }
929
987
}
930
988
931
989
/// <summary>
@@ -935,7 +993,7 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
935
993
/// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
936
994
/// <param name="userId">Docusign user Id to be impersonated(This is a UUID)</param>
937
995
/// <param name="oauthBasePath"> Docusign OAuth base path
938
- /// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/> <see cref="OAuth.Stage_OAuth_BasePath"/>
996
+ /// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/>
939
997
/// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
940
998
/// </param>
941
999
/// <param name="privateKeyStream">The Stream of the RSA private key</param>
@@ -945,12 +1003,12 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
945
1003
/// <see cref="OAuth.Scope_SIGNATURE"/> <see cref="OAuth.Scope_IMPERSONATION"/> <see cref="OAuth.Scope_EXTENDED"/>
946
1004
/// </param>
947
1005
/// <returns>The JWT user token</returns>
948
- public Task < OAuth . OAuthToken > RequestJWTUserTokenAsync ( string clientId , string userId , string oauthBasePath , Stream privateKeyStream , int expiresInHours , List < string > scopes = null , CancellationToken cancellationToken = default )
1006
+ public async Task < OAuth . OAuthToken > RequestJWTUserTokenAsync ( string clientId , string userId , string oauthBasePath , Stream privateKeyStream , int expiresInHours , List < string > scopes = null , CancellationToken cancellationToken = default )
949
1007
{
950
1008
if ( privateKeyStream != null && privateKeyStream . CanRead && privateKeyStream . Length > 0 )
951
1009
{
952
1010
byte [ ] privateKeyBytes = ReadAsBytes ( privateKeyStream ) ;
953
- return this . RequestJWTUserTokenAsync ( clientId , userId , oauthBasePath , privateKeyBytes , expiresInHours , scopes , cancellationToken ) ;
1011
+ return await this . RequestJWTUserTokenAsync ( clientId , userId , oauthBasePath , privateKeyBytes , expiresInHours , scopes , cancellationToken ) ;
954
1012
}
955
1013
else
956
1014
{
@@ -965,7 +1023,7 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
965
1023
/// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
966
1024
/// <param name="userId">Docusign user Id to be impersonated(This is a UUID)</param>
967
1025
/// <param name="oauthBasePath"> Docusign OAuth base path
968
- /// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/> <see cref="OAuth.Stage_OAuth_BasePath"/>
1026
+ /// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/>
969
1027
/// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
970
1028
/// </param>
971
1029
/// <param name="privateKeyBytes">The byte contents of the RSA private key</param>
@@ -976,8 +1034,15 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
976
1034
/// <returns>The JWT user token</returns>
977
1035
public OAuth . OAuthToken RequestJWTUserToken ( string clientId , string userId , string oauthBasePath , byte [ ] privateKeyBytes , int expiresInHours , List < string > scopes = null )
978
1036
{
979
- CancellationTokenSource cts = new CancellationTokenSource ( ) ;
980
- return TryCatchWrapper ( ( ) => RequestJWTUserTokenAsync ( clientId , userId , oauthBasePath , privateKeyBytes , expiresInHours , scopes , cts . Token ) . ConfigureAwait ( false ) . GetAwaiter ( ) . GetResult ( ) ) ;
1037
+
1038
+ using ( var cts = new CancellationTokenSource ( ) )
1039
+ {
1040
+ return TryCatchWrapper ( ( ) => {
1041
+ var task = Task . Run ( async ( ) => await RequestJWTUserTokenAsync ( clientId , userId , oauthBasePath , privateKeyBytes , expiresInHours , scopes , cts . Token ) ) ;
1042
+ task . Wait ( ) ;
1043
+ return task . Result ;
1044
+ } ) ;
1045
+ }
981
1046
}
982
1047
983
1048
/// <summary>
@@ -987,7 +1052,7 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
987
1052
/// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
988
1053
/// <param name="userId">Docusign user Id to be impersonated(This is a UUID)</param>
989
1054
/// <param name="oauthBasePath"> Docusign OAuth base path
990
- /// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/> <see cref="OAuth.Stage_OAuth_BasePath"/>
1055
+ /// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/>
991
1056
/// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
992
1057
/// </param>
993
1058
/// <param name="privateKeyBytes">The byte contents of the RSA private key</param>
@@ -1068,7 +1133,7 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
1068
1133
/// </summary>
1069
1134
/// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
1070
1135
/// <param name="oauthBasePath"> Docusign OAuth base path
1071
- /// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/> <see cref="OAuth.Stage_OAuth_BasePath"/>
1136
+ /// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/>
1072
1137
/// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
1073
1138
/// </param>
1074
1139
/// <param name="privateKeyBytes">The byte contents of the RSA private key</param>
@@ -1079,16 +1144,22 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
1079
1144
/// <returns>The JWT application token</returns>
1080
1145
public OAuth . OAuthToken RequestJWTApplicationToken ( string clientId , string oauthBasePath , byte [ ] privateKeyBytes , int expiresInHours , List < string > scopes = null )
1081
1146
{
1082
- CancellationTokenSource cts = new CancellationTokenSource ( ) ;
1083
- return TryCatchWrapper ( ( ) => RequestJWTApplicationTokenAsync ( clientId , oAuthBasePath , privateKeyBytes , expiresInHours , scopes , cts . Token ) . ConfigureAwait ( false ) . GetAwaiter ( ) . GetResult ( ) ) ;
1147
+ using ( var cts = new CancellationTokenSource ( ) )
1148
+ {
1149
+ return TryCatchWrapper ( ( ) => {
1150
+ var task = Task . Run ( async ( ) => await RequestJWTApplicationTokenAsync ( clientId , oAuthBasePath , privateKeyBytes , expiresInHours , scopes , cts . Token ) ) ;
1151
+ task . Wait ( ) ;
1152
+ return task . Result ;
1153
+ } ) ;
1154
+ }
1084
1155
}
1085
1156
1086
1157
/// <summary>
1087
1158
/// *RESERVED FOR PARTNERS* RequestJWTApplicationTokenAsync
1088
1159
/// </summary>
1089
1160
/// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
1090
1161
/// <param name="oauthBasePath"> Docusign OAuth base path
1091
- /// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/> <see cref="OAuth.Stage_OAuth_BasePath"/>
1162
+ /// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/>
1092
1163
/// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
1093
1164
/// </param>
1094
1165
/// <param name="privateKeyBytes">The byte contents of the RSA private key</param>
0 commit comments