diff --git a/resources/sdk/pureclouddotnet/extensions/Client/AbstractHttpClient.cs b/resources/sdk/pureclouddotnet/extensions/Client/AbstractHttpClient.cs
index 4ad6286c..059520e0 100644
--- a/resources/sdk/pureclouddotnet/extensions/Client/AbstractHttpClient.cs
+++ b/resources/sdk/pureclouddotnet/extensions/Client/AbstractHttpClient.cs
@@ -10,6 +10,20 @@
namespace {{=it.packageName }}.Client
{
+ ///
+ /// Delegate for pre-request hooks
+ ///
+ /// The HTTP request to be modified
+ /// Modified HTTP request
+ public delegate IHttpRequest PreRequestHook(IHttpRequest request);
+
+ ///
+ /// Delegate for post-request hooks
+ ///
+ /// The HTTP response to be modified
+ /// Modified HTTP response
+ public delegate IHttpResponse PostRequestHook(IHttpResponse response);
+
///
/// Abstract base class for HTTP client implementations that provides common functionality for making HTTP requests
///
@@ -27,6 +41,16 @@ public abstract class AbstractHttpClient
/// The User-Agent string
protected string UserAgent { get; set; } = "null";
+ ///
+ /// Pre-request hook that will be called before each request
+ ///
+ protected PreRequestHook PreHook { get; set; }
+
+ ///
+ /// Post-request hook that will be called after each request
+ ///
+ protected PostRequestHook PostHook { get; set; }
+
///
/// Sets the request timeout
///
@@ -51,6 +75,68 @@ public void SetUserAgent(string userAgent)
UserAgent = userAgent;
}
+ ///
+ /// Sets the pre-request hook
+ ///
+ /// The hook function to call before each request
+ public void SetPreRequestHook(PreRequestHook hook)
+ {
+ PreHook = hook;
+ }
+
+ ///
+ /// Sets the post-request hook
+ ///
+ /// The hook function to call after each request
+ public void SetPostRequestHook(PostRequestHook hook)
+ {
+ PostHook = hook;
+ }
+
+ ///
+ /// Applies the pre-request hook if set
+ ///
+ /// The original request
+ /// The modified request
+ protected IHttpRequest ApplyPreRequestHook(IHttpRequest request)
+ {
+ if (PreHook != null)
+ {
+ try
+ {
+ return PreHook(request);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error in pre-request hook: {ex.Message}");
+ throw ex;
+ }
+ }
+ return request;
+ }
+
+ ///
+ /// Applies the post-request hook if set
+ ///
+ /// The original response
+ /// The modified response
+ protected IHttpResponse ApplyPostRequestHook(IHttpResponse response)
+ {
+ if (PostHook != null)
+ {
+ try
+ {
+ return PostHook(response);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error in post-request hook: {ex.Message}");
+ throw ex;
+ }
+ }
+ return response;
+ }
+
///
/// Asynchronously executes an HTTP request
///
diff --git a/resources/sdk/pureclouddotnet/extensions/Client/DefaultHttpClient.cs b/resources/sdk/pureclouddotnet/extensions/Client/DefaultHttpClient.cs
index a14a8cec..d74d1a66 100644
--- a/resources/sdk/pureclouddotnet/extensions/Client/DefaultHttpClient.cs
+++ b/resources/sdk/pureclouddotnet/extensions/Client/DefaultHttpClient.cs
@@ -114,6 +114,9 @@ private bool ValidateServerCertificate(object sender, X509Certificate certificat
///
public override async Task ExecuteAsync(IHttpRequest httpRequest, CancellationToken cancellationToken = default(CancellationToken))
{
+ httpRequest = ApplyPreRequestHook(httpRequest);
+ IHttpResponse resp;
+
if (usingMTLS) //using HttpWebRequest
{
var request = PrepareWebRequest((HttpRequestOptions)httpRequest);
@@ -140,7 +143,7 @@ private bool ValidateServerCertificate(object sender, X509Certificate certificat
{
using (var response = (HttpWebResponse)await request.GetResponseAsync())
{
- return await ConvertToHttpResponse(response);
+ resp = await ConvertToHttpResponse(response);
}
}
catch (WebException ex)
@@ -158,8 +161,10 @@ private bool ValidateServerCertificate(object sender, X509Certificate certificat
var restResp = await restClient.ExecuteAsync(request, cancellationToken);
- return ConvertToHttpResponse(restResp);
+ resp = ConvertToHttpResponse(restResp);
}
+
+ return ApplyPostRequestHook(resp);
}
///
@@ -167,18 +172,24 @@ private bool ValidateServerCertificate(object sender, X509Certificate certificat
///
public override IHttpResponse Execute(IHttpRequest httpRequest)
{
+ IHttpResponse resp;
+
if (usingMTLS) //using HttpWebRequest
{
- return ExecuteAsync(httpRequest).GetAwaiter().GetResult();
+ resp = ExecuteAsync(httpRequest).GetAwaiter().GetResult();
}
else //using RestSharp (HttpClient)
{
+ httpRequest = ApplyPreRequestHook(httpRequest);
var request = PrepareRestRequest((HttpRequestOptions)httpRequest);
var restResp = restClient.Execute(request);
- return ConvertToHttpResponse(restResp);
+ resp = ConvertToHttpResponse(restResp);
+ resp = ApplyPostRequestHook(resp);
}
+
+ return resp;
}
private IHttpResponse ConvertToHttpResponse(RestResponse response)
diff --git a/resources/sdk/pureclouddotnet/templates/README.mustache b/resources/sdk/pureclouddotnet/templates/README.mustache
index 209f9310..e82297a9 100644
--- a/resources/sdk/pureclouddotnet/templates/README.mustache
+++ b/resources/sdk/pureclouddotnet/templates/README.mustache
@@ -633,6 +633,39 @@ var certPass = "x509Password";
Configuration.Default.ApiClient.SetMTLSCertificates(certPath, certPass);
```
+### Using Pre Commit and Post Commit Hooks
+
+For any custom requirements like pre validations or post cleanups (for ex: OCSP and CRL validation), we can inject the prehook and posthook functions.
+The SDK's default client will make sure the injected hook functions are executed.
+
+The Pre/Post Hook functions must have the following method signature shown below
+
+```csharp
+IHttpRequest preHook(IHttpRequest request)
+IHttpResponse postHook(IHttpRepsonse response)
+```
+
+Here is an example of using a Pre Hook function:
+
+```csharp
+private IHttpRequest preHook(IHttpRequest request)
+{
+ try {
+ Console.WriteLine("Running PreHook: Certificate Validation Checks");
+
+ // custom validation here
+
+ Console.WriteLine("Certificate Validation Complete");
+ } catch (Exception ex) {
+ Console.WriteLine($"Error in prehook validation: {ex.Message}");
+ throw ex; // Reject request if validation fails
+ }
+}
+
+Configuration.Default.ApiClient.HttpClient.SetPreRequestHook(preHook);
+
+```
+
### Building from Source
If you're working inside Visual Studio, adding the files to your project allows you to edit and build inside an IDE.
diff --git a/resources/sdk/pureclouddotnet/templates/test-SdkTests.mustache b/resources/sdk/pureclouddotnet/templates/test-SdkTests.mustache
index d078885b..b326073d 100644
--- a/resources/sdk/pureclouddotnet/templates/test-SdkTests.mustache
+++ b/resources/sdk/pureclouddotnet/templates/test-SdkTests.mustache
@@ -39,6 +39,31 @@ namespace {{packageName}}.Tests
string busyPresenceId = "31fe3bac-dea6-44b7-bed7-47f91660a1a0";
string availablePresenceId = "6a3af858-942f-489d-9700-5f9bcdcdae9b";
+ bool preHookCalled = false;
+ bool postHookCalled = false;
+ private IHttpRequest preHook(IHttpRequest request)
+ {
+ preHookCalled = true;
+ Console.WriteLine("Running Pre-Request Hook");
+ var options = (HttpRequestOptions)request;
+
+ options.AddHeaderParam("Test-Header", "Pre-Hook-Test");
+
+ Console.WriteLine($"Pre-Hook: Making {options.Method} request to {options.Url}");
+
+ return request;
+ }
+
+ private IHttpResponse postHook(IHttpResponse response)
+ {
+ postHookCalled = true;
+ Console.WriteLine("Running Post-Request Hook");
+
+ Console.WriteLine($"Post-Hook: Received status code {response.StatusCode}");
+
+ return response;
+ }
+
///
/// SdkTests default constructor
///
@@ -207,18 +232,27 @@ namespace {{packageName}}.Tests
[Test, Retry(2), Order(6)]
public void GetUser()
{
- Thread.Sleep(6000);
- var user = usersApi.GetUserWithHttpInfo(userId, new List() { "profileSkills" }, null, null);
- Assert.AreEqual(user.Data.Id, userId);
- Assert.AreEqual(user.Data.Name, userName);
- Assert.AreEqual(user.Data.Email, userEmail);
- Assert.AreEqual(user.Data.Department, userDepartment);
- Console.WriteLine($"CorrelationId for GetUserWithHttpInfo {user.CorrelationId}");
- Console.WriteLine($"Version for GetUserWithHttpInfo {user.Data.Version}");
- // Commented out until the issue with APIs to send the latest Version of the User is fixed.
- // Assert.IsNotNull(user.Data.ProfileSkills);
- // Assert.AreEqual(user.Data.ProfileSkills.Count, 1);
- // Assert.AreEqual(user.Data.ProfileSkills[0], userProfileSkill);
+ {{packageName}}.Client.Configuration.Default.ApiClient.HttpClient.SetPreRequestHook(preHook);
+ {{packageName}}.Client.Configuration.Default.ApiClient.HttpClient.SetPostRequestHook(postHook);
+
+ Thread.Sleep(6000);
+ var user = usersApi.GetUserWithHttpInfo(userId, new List() { "profileSkills" }, null, null);
+
+ Assert.IsTrue(preHookCalled, "Pre-Hook was not called");
+ Assert.IsTrue(postHookCalled, "Post-Hook was not called");
+ Assert.AreEqual(user.Data.Id, userId);
+ Assert.AreEqual(user.Data.Name, userName);
+ Assert.AreEqual(user.Data.Email, userEmail);
+ Assert.AreEqual(user.Data.Department, userDepartment);
+ Console.WriteLine($"CorrelationId for GetUserWithHttpInfo {user.CorrelationId}");
+ Console.WriteLine($"Version for GetUserWithHttpInfo {user.Data.Version}");
+ // Commented out until the issue with APIs to send the latest Version of the User is fixed.
+ // Assert.IsNotNull(user.Data.ProfileSkills);
+ // Assert.AreEqual(user.Data.ProfileSkills.Count, 1);
+ // Assert.AreEqual(user.Data.ProfileSkills[0], userProfileSkill);
+
+ {{packageName}}.Client.Configuration.Default.ApiClient.HttpClient.SetPreRequestHook(null);
+ {{packageName}}.Client.Configuration.Default.ApiClient.HttpClient.SetPostRequestHook(null);
}
///
@@ -309,6 +343,31 @@ namespace {{packageName}}.Tests
string userName = ".NET SDK MTLS Tester";
string userDepartment = "Ministry of MTLS Testing";
+ bool preHookCalled = false;
+ bool postHookCalled = false;
+ private IHttpRequest preHook(IHttpRequest request)
+ {
+ preHookCalled = true;
+ Console.WriteLine("Running Pre-Request Hook");
+ var options = (HttpRequestOptions)request;
+
+ options.AddHeaderParam("Test-Header", "Pre-Hook-Test");
+
+ Console.WriteLine($"Pre-Hook: Making {options.Method} request to {options.Url}");
+
+ return request;
+ }
+
+ private IHttpResponse postHook(IHttpResponse response)
+ {
+ postHookCalled = true;
+ Console.WriteLine("Running Post-Request Hook");
+
+ Console.WriteLine($"Post-Hook: Received status code {response.StatusCode}");
+
+ return response;
+ }
+
///
/// MTLSTests default constructor
///
@@ -414,6 +473,9 @@ namespace {{packageName}}.Tests
[Test, Order(4)]
public void UpdateUser()
{
+ {{packageName}}.Client.Configuration.Default.ApiClient.HttpClient.SetPreRequestHook(preHook);
+ {{packageName}}.Client.Configuration.Default.ApiClient.HttpClient.SetPostRequestHook(postHook);
+
var updateUser = new UpdateUser()
{
Department = userDepartment,
@@ -422,10 +484,15 @@ namespace {{packageName}}.Tests
var user = usersApi.PatchUser(userId, updateUser);
+ Assert.IsTrue(preHookCalled, "Pre-Hook was not called");
+ Assert.IsTrue(postHookCalled, "Post-Hook was not called");
Assert.AreEqual(user.Id, userId);
Assert.AreEqual(user.Name, userName);
Assert.AreEqual(user.Email, userEmail);
Assert.AreEqual(user.Department, userDepartment);
+
+ {{packageName}}.Client.Configuration.Default.ApiClient.HttpClient.SetPreRequestHook(null);
+ {{packageName}}.Client.Configuration.Default.ApiClient.HttpClient.SetPostRequestHook(null);
}
///
@@ -455,6 +522,9 @@ namespace {{packageName}}.Tests
Console.WriteLine($"Deleted user with ID {userId}");
}
+ ///
+ /// CleanUp
+ ///
[Test, Order(7)]
public void CleanUp()
{