Improve JSON handling and HTML encoding in API helpers#4489
Conversation
Refactored WireMockAPI to use System.Text.Json for payload serialization and robust JSON parsing for stub mappings. Enhanced GenAIServiceHelper to HTML-encode error logs and multipart form data, ensuring safer handling of special characters and null values.
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughTwo utility classes receive targeted updates: Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 0/1 reviews remaining, refill in 33 minutes and 40 seconds.Comment |
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 5 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Ginger/GingerCoreNET/External/WireMock/WireMockAPI.cs`:
- Around line 159-168: Extract the duplicated JSON normalization into a single
private helper (e.g., NormalizeStubMappingBody) and replace the parse/normalize
blocks inside CreateStubAsync and UpdateStubAsync with calls to that helper; the
helper should return string.Empty for null/empty input and otherwise parse with
JsonDocument and return doc.RootElement.GetRawText(), ensuring both
CreateStubAsync and UpdateStubAsync use it to avoid duplication and future
drift.
- Around line 103-104: Add a fail-fast guard in the WireMockAPI routine that
posts the recording config: check the targetUrl parameter (the variable named
targetUrl used when building the JSON and StringContent) for null or whitespace
before calling JsonSerializer.Serialize or issuing the HTTP request; if invalid,
log an error via the existing logger and return early (or throw a descriptive
ArgumentException) instead of proceeding to create content and post, so the
validation failure is handled locally in the method that constructs the
recording config.
- Around line 160-170: The null handling for stubMapping is incorrect: when
stubMapping is null you assign body = null which causes new StringContent(body,
...) to throw; in the methods that contain this logic (the WireMockAPI class
methods that build the request body—e.g., CreateStubAsync and UpdateStubAsync)
add an explicit null check for stubMapping and return early (or throw a clear,
documented exception) before constructing StringContent, and keep the
empty-string case separate (if stubMapping == "" set body = "" else parse JSON
into body via JsonDocument.Parse). Ensure you reference the stubMapping -> body
-> new StringContent(...) flow and apply the same fix in both affected blocks.
In `@Ginger/GingerCoreNET/GenAIServices/GenAIServiceHelper.cs`:
- Around line 108-109: The two duplicate Reporter.ToLog calls in
GenAIServiceHelper.cs (the ones using WebUtility.HtmlEncode on
ex.Message/InnerException/StackTrace) should be consolidated into a single call
that passes the exception object directly to Reporter.ToLog (following the
established pattern), removing the HTML-encoding and the explicit
stack-trace/inner-exception string logging; locate the Reporter.ToLog
invocations in the method where 'ex' is caught and replace them with a single
Reporter.ToLog(eLogLevel.ERROR, error, ex) (or equivalent overload) so log4net
handles formatting/encoding and no sensitive stack text is output manually.
- Around line 249-253: The multipart form fields are being HTML-encoded which
corrupts their values; remove WebUtility.HtmlEncode when creating StringContent
for the AskLisaConfiguration fields so they are sent raw like the "question"
field. Replace occurrences that wrap
CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.Account/DomainType/TemperatureLevel/MaxTokenValue/DataPath)
with simple StringContent(CredentialsCalculation(...) ?? string.Empty)
(preserving the same field names
"account","domainType","temperatureVal","maxTokensVal","dataPath") so the
multipart form data is not HTML-encoded.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 087e22a8-a2d2-4ef2-b82a-eefc96cdd8e8
📒 Files selected for processing (2)
Ginger/GingerCoreNET/External/WireMock/WireMockAPI.csGinger/GingerCoreNET/GenAIServices/GenAIServiceHelper.cs
| string json = JsonSerializer.Serialize(new { targetBaseUrl = targetUrl }); | ||
| var content = new StringContent(json, Encoding.UTF8, "application/json"); |
There was a problem hiding this comment.
Add a fail-fast guard for targetUrl before posting recording config.
Line 103 will serialize null/whitespace values and still issue the HTTP request, pushing validation failure downstream into a generic catch path. Validate input up front and return early with an error log.
Suggested patch
public async Task<string> StartRecordingAsync(string targetUrl)
{
try
{
if (string.IsNullOrEmpty(_baseUrl))
{
return string.Empty;
}
+ if (string.IsNullOrWhiteSpace(targetUrl))
+ {
+ Reporter.ToLog(eLogLevel.ERROR, "Target URL cannot be empty when starting WireMock recording");
+ return string.Empty;
+ }
using (HttpClient client = new HttpClient())
{
string json = JsonSerializer.Serialize(new { targetBaseUrl = targetUrl });
var content = new StringContent(json, Encoding.UTF8, "application/json");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Ginger/GingerCoreNET/External/WireMock/WireMockAPI.cs` around lines 103 -
104, Add a fail-fast guard in the WireMockAPI routine that posts the recording
config: check the targetUrl parameter (the variable named targetUrl used when
building the JSON and StringContent) for null or whitespace before calling
JsonSerializer.Serialize or issuing the HTTP request; if invalid, log an error
via the existing logger and return early (or throw a descriptive
ArgumentException) instead of proceeding to create content and post, so the
validation failure is handled locally in the method that constructs the
recording config.
| string body; | ||
| if (string.IsNullOrEmpty(stubMapping)) | ||
| { | ||
| body = stubMapping; | ||
| } | ||
| else | ||
| { | ||
| using JsonDocument doc = JsonDocument.Parse(stubMapping); | ||
| body = doc.RootElement.GetRawText(); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Extract JSON-body normalization into a shared helper.
The same parse/normalize block is duplicated in CreateStubAsync and UpdateStubAsync. Centralizing this logic will prevent drift and simplify future validation changes.
Refactor direction
- string body;
- if (string.IsNullOrEmpty(stubMapping))
- {
- body = stubMapping;
- }
- else
- {
- using JsonDocument doc = JsonDocument.Parse(stubMapping);
- body = doc.RootElement.GetRawText();
- }
+ string body = NormalizeStubMappingBody(stubMapping);private static string NormalizeStubMappingBody(string stubMapping)
{
if (stubMapping is null) return string.Empty;
if (stubMapping.Length == 0) return string.Empty;
using JsonDocument doc = JsonDocument.Parse(stubMapping);
return doc.RootElement.GetRawText();
}Also applies to: 221-230
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Ginger/GingerCoreNET/External/WireMock/WireMockAPI.cs` around lines 159 -
168, Extract the duplicated JSON normalization into a single private helper
(e.g., NormalizeStubMappingBody) and replace the parse/normalize blocks inside
CreateStubAsync and UpdateStubAsync with calls to that helper; the helper should
return string.Empty for null/empty input and otherwise parse with JsonDocument
and return doc.RootElement.GetRawText(), ensuring both CreateStubAsync and
UpdateStubAsync use it to avoid duplication and future drift.
| if (string.IsNullOrEmpty(stubMapping)) | ||
| { | ||
| body = stubMapping; | ||
| } | ||
| else | ||
| { | ||
| using JsonDocument doc = JsonDocument.Parse(stubMapping); | ||
| body = doc.RootElement.GetRawText(); | ||
| } | ||
|
|
||
| var content = new StringContent(body, Encoding.UTF8, contentType); |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In .NET, does new StringContent((string)null, Encoding.UTF8, "application/json")throwArgumentNullException?
💡 Result:
Yes, new StringContent((string)null, Encoding.UTF8, "application/json") throws an ArgumentNullException.
Citations:
- 1: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Http/src/System/Net/Http/StringContent.cs
- 2: https://github.com/dotnet/dotnet/blob/17d11de66cf75b962995c81dd1235fae9aa5ece0/src/runtime/src/libraries/System.Net.Http/src/System/Net/Http/StringContent.cs
🏁 Script executed:
fd -t f "WireMockAPI.cs" | head -5Repository: Ginger-Automation/Ginger
Length of output: 122
🏁 Script executed:
fd -t f "WireMockAPI.cs" --exec cat -n {} \; | sed -n '155,240p'Repository: Ginger-Automation/Ginger
Length of output: 4085
🏁 Script executed:
rg "Reporter\.ToLog\(eLogLevel\.ERROR" -t cs | head -10Repository: Ginger-Automation/Ginger
Length of output: 1643
Null stubMapping causes ArgumentNullException at StringContent construction.
The code at lines 160–170 and 221–233 contains a logic error: when stubMapping is null, the condition string.IsNullOrEmpty(stubMapping) evaluates to true, and body is assigned the null value. This causes new StringContent(body, ...) to throw ArgumentNullException before the request is sent, making null handling brittle.
Separate the null check from the empty check and return early:
Suggested fix
string body;
if (stubMapping is null)
{
Reporter.ToLog(eLogLevel.ERROR, "Stub mapping cannot be null");
return string.Empty;
}
else if (stubMapping.Length == 0)
{
body = string.Empty;
}
else
{
using JsonDocument doc = JsonDocument.Parse(stubMapping);
body = doc.RootElement.GetRawText();
}Also applies to lines 221–233 in UpdateStubAsync.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Ginger/GingerCoreNET/External/WireMock/WireMockAPI.cs` around lines 160 -
170, The null handling for stubMapping is incorrect: when stubMapping is null
you assign body = null which causes new StringContent(body, ...) to throw; in
the methods that contain this logic (the WireMockAPI class methods that build
the request body—e.g., CreateStubAsync and UpdateStubAsync) add an explicit null
check for stubMapping and return early (or throw a clear, documented exception)
before constructing StringContent, and keep the empty-string case separate (if
stubMapping == "" set body = "" else parse JSON into body via
JsonDocument.Parse). Ensure you reference the stubMapping -> body -> new
StringContent(...) flow and apply the same fix in both affected blocks.
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.Account) ?? string.Empty)), "account" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DomainType) ?? string.Empty)), "domainType" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.TemperatureLevel) ?? string.Empty)), "temperatureVal" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.MaxTokenValue) ?? string.Empty)), "maxTokensVal" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DataPath) ?? string.Empty)), "dataPath" } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check if the file exists and examine the code at lines 249-253
fd 'GenAIServiceHelper.cs' --type fRepository: Ginger-Automation/Ginger
Length of output: 125
🏁 Script executed:
# Examine the code at lines 249-253 and surrounding context
cat -n Ginger/GingerCoreNET/GenAIServices/GenAIServiceHelper.cs | sed -n '240,260p'Repository: Ginger-Automation/Ginger
Length of output: 1445
🏁 Script executed:
# Search for other uses of HtmlEncode in this file and similar patterns
rg -n "HtmlEncode" Ginger/GingerCoreNET/GenAIServices/GenAIServiceHelper.csRepository: Ginger-Automation/Ginger
Length of output: 1380
🏁 Script executed:
# Look for how this PrepareRequestDetailsForChat method is used
rg -n "PrepareRequestDetailsForChat" Ginger/GingerCoreNET/GenAIServices/GenAIServiceHelper.cs -A 5 -B 2Repository: Ginger-Automation/Ginger
Length of output: 1396
🏁 Script executed:
# Check the Question parameter - it's not HTML encoded, let's verify multipart form data best practices
# Also look for similar patterns in the codebase with MultipartFormDataContent
rg -n "MultipartFormDataContent" Ginger/GingerCoreNET/GenAIServices/ -A 10 | head -80Repository: Ginger-Automation/Ginger
Length of output: 4516
🏁 Script executed:
# Check the complete method signature and context to understand what API endpoint is being called
cat -n Ginger/GingerCoreNET/GenAIServices/GenAIServiceHelper.cs | sed -n '1,20p'Repository: Ginger-Automation/Ginger
Length of output: 878
🏁 Script executed:
# Check git history or comments to see if there's a reason for HtmlEncode
cat -n Ginger/GingerCoreNET/GenAIServices/GenAIServiceHelper.cs | sed -n '244,256p'Repository: Ginger-Automation/Ginger
Length of output: 1328
🏁 Script executed:
# Check for any documentation or comments about why HtmlEncode is used
cat -n Ginger/GingerCoreNET/GenAIServices/GenAIServiceHelper.cs | sed -n '155,195p'Repository: Ginger-Automation/Ginger
Length of output: 1954
🏁 Script executed:
# Check the complete file to understand class structure and imports
wc -l Ginger/GingerCoreNET/GenAIServices/GenAIServiceHelper.csRepository: Ginger-Automation/Ginger
Length of output: 129
Remove WebUtility.HtmlEncode() calls from multipart form data fields.
At lines 249-253, HTML encoding corrupts the form field values for an HTTP multipart request. Multipart form data is not HTML content and should not be HTML-encoded; special characters like &, <, > will be converted to entities (&, <, >), breaking the API contract. The "question" field at line 248 is correctly sent unencoded—apply the same approach to all form fields.
Suggested fix
- { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.Account) ?? string.Empty)), "account" },
- { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DomainType) ?? string.Empty)), "domainType" },
- { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.TemperatureLevel) ?? string.Empty)), "temperatureVal" },
- { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.MaxTokenValue) ?? string.Empty)), "maxTokensVal" },
- { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DataPath) ?? string.Empty)), "dataPath" }
+ { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.Account) ?? string.Empty), "account" },
+ { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DomainType) ?? string.Empty), "domainType" },
+ { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.TemperatureLevel) ?? string.Empty), "temperatureVal" },
+ { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.MaxTokenValue) ?? string.Empty), "maxTokensVal" },
+ { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DataPath) ?? string.Empty), "dataPath" }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.Account) ?? string.Empty)), "account" }, | |
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DomainType) ?? string.Empty)), "domainType" }, | |
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.TemperatureLevel) ?? string.Empty)), "temperatureVal" }, | |
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.MaxTokenValue) ?? string.Empty)), "maxTokensVal" }, | |
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DataPath) ?? string.Empty)), "dataPath" } | |
| { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.Account) ?? string.Empty), "account" }, | |
| { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DomainType) ?? string.Empty), "domainType" }, | |
| { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.TemperatureLevel) ?? string.Empty), "temperatureVal" }, | |
| { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.MaxTokenValue) ?? string.Empty), "maxTokensVal" }, | |
| { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DataPath) ?? string.Empty), "dataPath" } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Ginger/GingerCoreNET/GenAIServices/GenAIServiceHelper.cs` around lines 249 -
253, The multipart form fields are being HTML-encoded which corrupts their
values; remove WebUtility.HtmlEncode when creating StringContent for the
AskLisaConfiguration fields so they are sent raw like the "question" field.
Replace occurrences that wrap
CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.Account/DomainType/TemperatureLevel/MaxTokenValue/DataPath)
with simple StringContent(CredentialsCalculation(...) ?? string.Empty)
(preserving the same field names
"account","domainType","temperatureVal","maxTokensVal","dataPath") so the
multipart form data is not HTML-encoded.
| body = doc.RootElement.GetRawText(); | ||
| } | ||
|
|
||
| var content = new StringContent(body, Encoding.UTF8, contentType); |
| { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.TemperatureLevel)), "temperatureVal" }, | ||
| { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.MaxTokenValue)), "maxTokensVal" }, | ||
| { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DataPath)), "dataPath" } | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.Account) ?? string.Empty)), "account" }, |
| { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.MaxTokenValue)), "maxTokensVal" }, | ||
| { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DataPath)), "dataPath" } | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.Account) ?? string.Empty)), "account" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DomainType) ?? string.Empty)), "domainType" }, |
| { new StringContent(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DataPath)), "dataPath" } | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.Account) ?? string.Empty)), "account" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DomainType) ?? string.Empty)), "domainType" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.TemperatureLevel) ?? string.Empty)), "temperatureVal" }, |
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.Account) ?? string.Empty)), "account" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DomainType) ?? string.Empty)), "domainType" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.TemperatureLevel) ?? string.Empty)), "temperatureVal" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.MaxTokenValue) ?? string.Empty)), "maxTokensVal" }, |
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DomainType) ?? string.Empty)), "domainType" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.TemperatureLevel) ?? string.Empty)), "temperatureVal" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.MaxTokenValue) ?? string.Empty)), "maxTokensVal" }, | ||
| { new StringContent(WebUtility.HtmlEncode(CredentialsCalculation(WorkSpace.Instance.Solution.AskLisaConfiguration.DataPath) ?? string.Empty)), "dataPath" } |
Simplified exception handling by replacing manual error message construction and encoding with a single Reporter.ToLog call that passes the exception object, leveraging built-in logging features.
Refactored WireMockAPI to use System.Text.Json for payload serialization and robust JSON parsing for stub mappings. Enhanced GenAIServiceHelper to HTML-encode error logs and multipart form data, ensuring safer handling of special characters and null values.
Description
Type of Change
Checklist
[IsSerializedForLocalRepository]where neededReporter.ToLog()patternSummary by CodeRabbit