@@ -43,8 +43,6 @@ public class DocuSignClient
4343 public const string Production_REST_BasePath = "https://www.docusign.net/restapi" ;
4444 // Sandbox/Demo base path
4545 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" ;
4846
4947 protected string basePath = Demo_REST_BasePath ;
5048
@@ -317,6 +315,47 @@ public string ParameterToString(object obj)
317315 return Convert . ToString ( obj ) ;
318316 }
319317
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+
320359 /// <summary>
321360 /// Deserialize the JSON string into a proper object.
322361 /// </summary>
@@ -345,6 +384,11 @@ public object Deserialize(DocuSignResponse response, Type type)
345384 return ConvertType ( response . Content , type ) ;
346385 }
347386
387+ if ( response . ContentType == "text/csv" )
388+ {
389+ return DeserializeStringToCsv ( response . Content ) ;
390+ }
391+
348392 // at this point, it must be a model (json)
349393 try
350394 {
@@ -724,10 +768,6 @@ public void SetOAuthBasePath(string oauthBaseUri = null)
724768 {
725769 this . oAuthBasePath = OAuth . Demo_OAuth_BasePath ;
726770 }
727- else if ( baseUri . Host . StartsWith ( "apps-s" ) || baseUri . Host . StartsWith ( "stage" ) )
728- {
729- this . oAuthBasePath = OAuth . Stage_OAuth_BasePath ;
730- }
731771 else
732772 {
733773 this . oAuthBasePath = OAuth . Production_OAuth_BasePath ;
@@ -774,8 +814,14 @@ private static T TryCatchWrapper<T>(Func<T> func)
774814 /// </returns>
775815 public OAuth . OAuthToken GenerateAccessToken ( string clientId , string clientSecret , string code )
776816 {
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+ }
779825 }
780826
781827 /// <summary>
@@ -790,7 +836,7 @@ public OAuth.OAuthToken GenerateAccessToken(string clientId, string clientSecret
790836 /// ApiException if the HTTP call status is different than 2xx.
791837 /// IOException if there is a problem while parsing the reponse object.
792838 /// </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 )
794840 {
795841 if ( string . IsNullOrEmpty ( clientId ) || string . IsNullOrEmpty ( clientSecret ) || string . IsNullOrEmpty ( code ) )
796842 {
@@ -840,8 +886,14 @@ public OAuth.OAuthToken GenerateAccessToken(string clientId, string clientSecret
840886 /// <returns>The User Info model.</returns>
841887 public OAuth . UserInfo GetUserInfo ( string accessToken )
842888 {
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+ }
845897 }
846898
847899 /// <summary>
@@ -850,7 +902,7 @@ public OAuth.UserInfo GetUserInfo(string accessToken)
850902 /// <param name="accessToken"></param>
851903 /// <param name="cancellationToken">A CancellationToken which can be used to propagate notification that operations should be canceled. </param>
852904 /// <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 )
854906 {
855907 if ( string . IsNullOrEmpty ( accessToken ) )
856908 {
@@ -913,7 +965,7 @@ protected static RSA CreateRSAKeyFromPem(string key)
913965 /// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
914966 /// <param name="userId">Docusign user Id to be impersonated(This is a UUID)</param>
915967 /// <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"/>
917969 /// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
918970 /// </param>
919971 /// <param name="privateKeyStream">The Stream of the RSA private key</param>
@@ -924,8 +976,14 @@ protected static RSA CreateRSAKeyFromPem(string key)
924976 /// <returns>The JWT user token</returns>
925977 public OAuth . OAuthToken RequestJWTUserToken ( string clientId , string userId , string oauthBasePath , Stream privateKeyStream , int expiresInHours , List < string > scopes = null )
926978 {
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+ }
929987 }
930988
931989 /// <summary>
@@ -935,7 +993,7 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
935993 /// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
936994 /// <param name="userId">Docusign user Id to be impersonated(This is a UUID)</param>
937995 /// <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"/>
939997 /// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
940998 /// </param>
941999 /// <param name="privateKeyStream">The Stream of the RSA private key</param>
@@ -945,12 +1003,12 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
9451003 /// <see cref="OAuth.Scope_SIGNATURE"/> <see cref="OAuth.Scope_IMPERSONATION"/> <see cref="OAuth.Scope_EXTENDED"/>
9461004 /// </param>
9471005 /// <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 )
9491007 {
9501008 if ( privateKeyStream != null && privateKeyStream . CanRead && privateKeyStream . Length > 0 )
9511009 {
9521010 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 ) ;
9541012 }
9551013 else
9561014 {
@@ -965,7 +1023,7 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
9651023 /// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
9661024 /// <param name="userId">Docusign user Id to be impersonated(This is a UUID)</param>
9671025 /// <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"/>
9691027 /// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
9701028 /// </param>
9711029 /// <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
9761034 /// <returns>The JWT user token</returns>
9771035 public OAuth . OAuthToken RequestJWTUserToken ( string clientId , string userId , string oauthBasePath , byte [ ] privateKeyBytes , int expiresInHours , List < string > scopes = null )
9781036 {
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+ }
9811046 }
9821047
9831048 /// <summary>
@@ -987,7 +1052,7 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
9871052 /// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
9881053 /// <param name="userId">Docusign user Id to be impersonated(This is a UUID)</param>
9891054 /// <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"/>
9911056 /// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
9921057 /// </param>
9931058 /// <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
10681133 /// </summary>
10691134 /// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
10701135 /// <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"/>
10721137 /// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
10731138 /// </param>
10741139 /// <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
10791144 /// <returns>The JWT application token</returns>
10801145 public OAuth . OAuthToken RequestJWTApplicationToken ( string clientId , string oauthBasePath , byte [ ] privateKeyBytes , int expiresInHours , List < string > scopes = null )
10811146 {
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+ }
10841155 }
10851156
10861157 /// <summary>
10871158 /// *RESERVED FOR PARTNERS* RequestJWTApplicationTokenAsync
10881159 /// </summary>
10891160 /// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
10901161 /// <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"/>
10921163 /// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
10931164 /// </param>
10941165 /// <param name="privateKeyBytes">The byte contents of the RSA private key</param>
0 commit comments