Skip to content

Commit

Permalink
Version 8.0.1-v2.1-24.2.00.00 release (#455)
Browse files Browse the repository at this point in the history
Co-authored-by: root <[email protected]>
  • Loading branch information
garg-mudit and root authored Nov 8, 2024
1 parent 200640f commit 598ee95
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 38 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# DocuSign C# Client Changelog

## [v8.0.1] - eSignature API v2.1-24.2.00.00 - 2024-11-07
### Changed
- Fixed Deadlock issue with UI Apps (E.g. WinForms).
- Fixed deserialization issue of text/csv type response
- Removed the staging base path and OAuth path constant.
- Updated the SDK release version.

## [v8.0.0] - eSignature API v2.1-24.2.00.00 - 2024-09-06
### Breaking Changes

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ This client SDK is provided as open source, which enables you to customize its f
<a id="versionInformation"></a>
### Version Information
- **API version**: v2.1
- **Latest SDK version (Including prerelease)**: 8.0.0
- **Latest SDK version (Including prerelease)**: 8.0.1

<a id="requirements"></a>
### Requirements
Expand Down
10 changes: 5 additions & 5 deletions sdk/DocuSign.eSign.sln
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
VisualStudioVersion = 12.0.0.0
MinimumVisualStudioVersion = 10.0.0.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocuSign.eSign", "src\DocuSign.eSign\DocuSign.eSign.csproj", "{50784E0B-2997-43AD-88AF-1400998CCD0F}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocuSign.eSign", "src\DocuSign.eSign\DocuSign.eSign.csproj", "{54EB3C5C-3432-4E2F-ADEC-DE1DE3934C2B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{50784E0B-2997-43AD-88AF-1400998CCD0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{50784E0B-2997-43AD-88AF-1400998CCD0F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{50784E0B-2997-43AD-88AF-1400998CCD0F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{50784E0B-2997-43AD-88AF-1400998CCD0F}.Release|Any CPU.Build.0 = Release|Any CPU
{54EB3C5C-3432-4E2F-ADEC-DE1DE3934C2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{54EB3C5C-3432-4E2F-ADEC-DE1DE3934C2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{54EB3C5C-3432-4E2F-ADEC-DE1DE3934C2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{54EB3C5C-3432-4E2F-ADEC-DE1DE3934C2B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
2 changes: 0 additions & 2 deletions sdk/src/DocuSign.eSign/Client/Auth/OAuth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ public class OAuth
public static string Demo_OAuth_BasePath = "account-d.docusign.com";
// Production server base path
public static string Production_OAuth_BasePath = "account.docusign.com";
// Stage server base path
public static string Stage_OAuth_BasePath = "account-s.docusign.com";

// OAuth ResponseType constants
// used by public/native client applications.
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/DocuSign.eSign/Client/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class Configuration
/// Version of the package.
/// </summary>
/// <value>Version of the package.</value>
public const string Version = "8.0.0";
public const string Version = "8.0.1";

/// <summary>
/// Identifier for ISO 8601 DateTime Format
Expand Down
123 changes: 97 additions & 26 deletions sdk/src/DocuSign.eSign/Client/DocuSignClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ public class DocuSignClient
public const string Production_REST_BasePath = "https://www.docusign.net/restapi";
// Sandbox/Demo base path
public const string Demo_REST_BasePath = "https://demo.docusign.net/restapi";
// Stage base path
public const string Stage_REST_BasePath = "https://stage.docusign.net/restapi";

protected string basePath = Demo_REST_BasePath;

Expand Down Expand Up @@ -317,6 +315,47 @@ public string ParameterToString(object obj)
return Convert.ToString(obj);
}

/// <summary>
/// Parses a CSV-formatted string and converts it into a list of dictionaries,
/// where each dictionary represents a record with column headers as keys.
/// </summary>
/// <param name="content">The CSV-formatted string to be deserialized.</param>
/// <returns>A list of dictionaries, each containing key-value pairs of column headers and their corresponding values.</returns>
private object DeserializeStringToCsv(string content)
{
var records = new List<Dictionary<string, object>>();

// Split the CSV string into lines
var lines = content.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

// Check if there are any lines
if (lines.Length > 0)
{
// Read the header line
string[] headers = lines[0].Split(',');

// Read the rest of the lines
for (int i = 1; i < lines.Length; i++)
{
string[] values = lines[i].Split(',');
var record = new Dictionary<string, object>();

for (int j = 0; j < headers.Length; j++)
{
// Ensure we don't exceed the number of values
if (j < values.Length)
{
record[headers[j]] = values[j]; // Store the value in the dictionary
}
}

records.Add(record); // Add the record to the list
}
}

return records; // Return the list of records
}

/// <summary>
/// Deserialize the JSON string into a proper object.
/// </summary>
Expand Down Expand Up @@ -345,6 +384,11 @@ public object Deserialize(DocuSignResponse response, Type type)
return ConvertType(response.Content, type);
}

if(response.ContentType == "text/csv")
{
return DeserializeStringToCsv(response.Content);
}

// at this point, it must be a model (json)
try
{
Expand Down Expand Up @@ -724,10 +768,6 @@ public void SetOAuthBasePath(string oauthBaseUri = null)
{
this.oAuthBasePath = OAuth.Demo_OAuth_BasePath;
}
else if (baseUri.Host.StartsWith("apps-s") || baseUri.Host.StartsWith("stage"))
{
this.oAuthBasePath = OAuth.Stage_OAuth_BasePath;
}
else
{
this.oAuthBasePath = OAuth.Production_OAuth_BasePath;
Expand Down Expand Up @@ -774,8 +814,14 @@ private static T TryCatchWrapper<T>(Func<T> func)
/// </returns>
public OAuth.OAuthToken GenerateAccessToken(string clientId, string clientSecret, string code)
{
CancellationTokenSource cts = new CancellationTokenSource();
return TryCatchWrapper(() => GenerateAccessTokenAsync(clientId, clientSecret, code, cts.Token).ConfigureAwait(false).GetAwaiter().GetResult());
using (var cts = new CancellationTokenSource())
{
return TryCatchWrapper(() => {
var task = Task.Run(async () => await GenerateAccessTokenAsync(clientId, clientSecret, code, cts.Token));
task.Wait();
return task.Result;
});
}
}

/// <summary>
Expand All @@ -790,7 +836,7 @@ public OAuth.OAuthToken GenerateAccessToken(string clientId, string clientSecret
/// ApiException if the HTTP call status is different than 2xx.
/// IOException if there is a problem while parsing the reponse object.
/// </returns>
public async Task<OAuth.OAuthToken> GenerateAccessTokenAsync(string clientId, string clientSecret, string code, CancellationToken cancellationToken)
public async Task<OAuth.OAuthToken> GenerateAccessTokenAsync(string clientId, string clientSecret, string code, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(clientSecret) || string.IsNullOrEmpty(code))
{
Expand Down Expand Up @@ -840,8 +886,14 @@ public OAuth.OAuthToken GenerateAccessToken(string clientId, string clientSecret
/// <returns>The User Info model.</returns>
public OAuth.UserInfo GetUserInfo(string accessToken)
{
CancellationTokenSource cts = new CancellationTokenSource();
return TryCatchWrapper(() => GetUserInfoAsync(accessToken, cts.Token).ConfigureAwait(false).GetAwaiter().GetResult());
using (var cts = new CancellationTokenSource())
{
return TryCatchWrapper(() => {
var task = Task.Run(async () => await GetUserInfoAsync(accessToken, cts.Token));
task.Wait();
return task.Result;
});
}
}

/// <summary>
Expand All @@ -850,7 +902,7 @@ public OAuth.UserInfo GetUserInfo(string accessToken)
/// <param name="accessToken"></param>
/// <param name="cancellationToken">A CancellationToken which can be used to propagate notification that operations should be canceled. </param>
/// <returns>The User Info model.</returns>
public async Task<OAuth.UserInfo> GetUserInfoAsync(string accessToken, CancellationToken cancellationToken)
public async Task<OAuth.UserInfo> GetUserInfoAsync(string accessToken, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(accessToken))
{
Expand Down Expand Up @@ -913,7 +965,7 @@ protected static RSA CreateRSAKeyFromPem(string key)
/// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
/// <param name="userId">Docusign user Id to be impersonated(This is a UUID)</param>
/// <param name="oauthBasePath"> Docusign OAuth base path
/// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/> <see cref="OAuth.Stage_OAuth_BasePath"/>
/// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/>
/// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
/// </param>
/// <param name="privateKeyStream">The Stream of the RSA private key</param>
Expand All @@ -924,8 +976,14 @@ protected static RSA CreateRSAKeyFromPem(string key)
/// <returns>The JWT user token</returns>
public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, string oauthBasePath, Stream privateKeyStream, int expiresInHours, List<string> scopes = null)
{
CancellationTokenSource cts = new CancellationTokenSource();
return TryCatchWrapper(() => RequestJWTUserTokenAsync(clientId, userId, oauthBasePath, privateKeyStream, expiresInHours, scopes, cts.Token).ConfigureAwait(false).GetAwaiter().GetResult());
using (var cts = new CancellationTokenSource())
{
return TryCatchWrapper(() => {
var task = Task.Run(async () => await RequestJWTUserTokenAsync(clientId, userId, oauthBasePath, privateKeyStream, expiresInHours, scopes, cts.Token));
task.Wait();
return task.Result;
});
}
}

/// <summary>
Expand All @@ -935,7 +993,7 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
/// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
/// <param name="userId">Docusign user Id to be impersonated(This is a UUID)</param>
/// <param name="oauthBasePath"> Docusign OAuth base path
/// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/> <see cref="OAuth.Stage_OAuth_BasePath"/>
/// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/>
/// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
/// </param>
/// <param name="privateKeyStream">The Stream of the RSA private key</param>
Expand All @@ -945,12 +1003,12 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
/// <see cref="OAuth.Scope_SIGNATURE"/> <see cref="OAuth.Scope_IMPERSONATION"/> <see cref="OAuth.Scope_EXTENDED"/>
/// </param>
/// <returns>The JWT user token</returns>
public Task<OAuth.OAuthToken> RequestJWTUserTokenAsync(string clientId, string userId, string oauthBasePath, Stream privateKeyStream, int expiresInHours, List<string> scopes = null, CancellationToken cancellationToken = default)
public async Task<OAuth.OAuthToken> RequestJWTUserTokenAsync(string clientId, string userId, string oauthBasePath, Stream privateKeyStream, int expiresInHours, List<string> scopes = null, CancellationToken cancellationToken = default)
{
if (privateKeyStream != null && privateKeyStream.CanRead && privateKeyStream.Length > 0)
{
byte[] privateKeyBytes = ReadAsBytes(privateKeyStream);
return this.RequestJWTUserTokenAsync(clientId, userId, oauthBasePath, privateKeyBytes, expiresInHours, scopes, cancellationToken);
return await this.RequestJWTUserTokenAsync(clientId, userId, oauthBasePath, privateKeyBytes, expiresInHours, scopes, cancellationToken);
}
else
{
Expand All @@ -965,7 +1023,7 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
/// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
/// <param name="userId">Docusign user Id to be impersonated(This is a UUID)</param>
/// <param name="oauthBasePath"> Docusign OAuth base path
/// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/> <see cref="OAuth.Stage_OAuth_BasePath"/>
/// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/>
/// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
/// </param>
/// <param name="privateKeyBytes">The byte contents of the RSA private key</param>
Expand All @@ -976,8 +1034,15 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
/// <returns>The JWT user token</returns>
public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, string oauthBasePath, byte[] privateKeyBytes, int expiresInHours, List<string> scopes = null)
{
CancellationTokenSource cts = new CancellationTokenSource();
return TryCatchWrapper(() => RequestJWTUserTokenAsync(clientId, userId, oauthBasePath, privateKeyBytes, expiresInHours, scopes, cts.Token).ConfigureAwait(false).GetAwaiter().GetResult());

using (var cts = new CancellationTokenSource())
{
return TryCatchWrapper(() => {
var task = Task.Run(async () => await RequestJWTUserTokenAsync(clientId, userId, oauthBasePath, privateKeyBytes, expiresInHours, scopes, cts.Token));
task.Wait();
return task.Result;
});
}
}

/// <summary>
Expand All @@ -987,7 +1052,7 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
/// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
/// <param name="userId">Docusign user Id to be impersonated(This is a UUID)</param>
/// <param name="oauthBasePath"> Docusign OAuth base path
/// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/> <see cref="OAuth.Stage_OAuth_BasePath"/>
/// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/>
/// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
/// </param>
/// <param name="privateKeyBytes">The byte contents of the RSA private key</param>
Expand Down Expand Up @@ -1068,7 +1133,7 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
/// </summary>
/// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
/// <param name="oauthBasePath"> Docusign OAuth base path
/// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/> <see cref="OAuth.Stage_OAuth_BasePath"/>
/// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/>
/// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
/// </param>
/// <param name="privateKeyBytes">The byte contents of the RSA private key</param>
Expand All @@ -1079,16 +1144,22 @@ public OAuth.OAuthToken RequestJWTUserToken(string clientId, string userId, stri
/// <returns>The JWT application token</returns>
public OAuth.OAuthToken RequestJWTApplicationToken(string clientId, string oauthBasePath, byte[] privateKeyBytes, int expiresInHours, List<string> scopes = null)
{
CancellationTokenSource cts = new CancellationTokenSource();
return TryCatchWrapper(() => RequestJWTApplicationTokenAsync(clientId, oAuthBasePath, privateKeyBytes, expiresInHours, scopes, cts.Token).ConfigureAwait(false).GetAwaiter().GetResult());
using (var cts = new CancellationTokenSource())
{
return TryCatchWrapper(() => {
var task = Task.Run(async () => await RequestJWTApplicationTokenAsync(clientId, oAuthBasePath, privateKeyBytes, expiresInHours, scopes, cts.Token));
task.Wait();
return task.Result;
});
}
}

/// <summary>
/// *RESERVED FOR PARTNERS* RequestJWTApplicationTokenAsync
/// </summary>
/// <param name="clientId">Docusign OAuth Client Id(AKA Integrator Key)</param>
/// <param name="oauthBasePath"> Docusign OAuth base path
/// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/> <see cref="OAuth.Stage_OAuth_BasePath"/>
/// <see cref="OAuth.Demo_OAuth_BasePath"/> <see cref="OAuth.Production_OAuth_BasePath"/>
/// <seealso cref="GetOAuthBasePath()" /> <seealso cref="SetOAuthBasePath(string)"/>
/// </param>
/// <param name="privateKeyBytes">The byte contents of the RSA private key</param>
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/DocuSign.eSign/DocuSign.eSign.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<RootNamespace>DocuSign.eSign</RootNamespace>
<AssemblyName>DocuSign.eSign</AssemblyName>
<NeutralLanguage>en-US</NeutralLanguage>
<VersionPrefix>8.0.0</VersionPrefix>
<VersionPrefix>8.0.1</VersionPrefix>
<VersionSuffix/>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand All @@ -26,7 +26,7 @@
<PackageLicenseUrl>https://github.com/docusign/docusign-esign-csharp-client/blob/master/LICENSE</PackageLicenseUrl>
<RepositoryUrl>https://github.com/docusign/docusign-esign-csharp-client</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageReleaseNotes>[v8.0.0] - ESignature API v2.1-24.2.00.00 - 9/6/2024</PackageReleaseNotes>
<PackageReleaseNotes>[v8.0.1] - ESignature API v2.1-24.2.00.00 - 11/7/2024</PackageReleaseNotes>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net462'">
<DefineConstants>NET462</DefineConstants>
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/DocuSign.eSign/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@
// [assembly: AssemblyVersion("1.0.*")]
internal class AssemblyInformation
{
public const string AssemblyInformationalVersion = "8.0.0";
public const string AssemblyInformationalVersion = "8.0.1";
}

0 comments on commit 598ee95

Please sign in to comment.