Skip to content

Commit e9de002

Browse files
committed
Fix project creation JSON serialization and improve error messages
- Add camelCase JSON serialization options to Blazor HttpClient - Update ProjectService to use shared JsonSerializerOptions - Improve ReadErrorMessageAsync to parse validation errors from API
1 parent a70c164 commit e9de002

2 files changed

Lines changed: 41 additions & 7 deletions

File tree

cloud/src/LrmCloud.Web/Program.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Text.Json;
12
using Microsoft.AspNetCore.Components.Web;
23
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
34
using Microsoft.AspNetCore.Components.Authorization;
@@ -33,6 +34,10 @@
3334
builder.Services.AddScoped<AuthenticationStateProvider>(sp => sp.GetRequiredService<LrmAuthStateProvider>());
3435
builder.Services.AddAuthorizationCore();
3536

37+
// JSON serialization options - use Web defaults (camelCase) to match API
38+
var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web);
39+
builder.Services.AddSingleton(jsonOptions);
40+
3641
// Configure HttpClient with API base URL and auth handler
3742
// Use the origin (scheme + host + port) with /api/ path, not relative to Blazor's /app/ base
3843
var baseUri = new Uri(builder.HostEnvironment.BaseAddress);

cloud/src/LrmCloud.Web/Services/ProjectService.cs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Net.Http.Json;
2+
using System.Text.Json;
23
using LrmCloud.Shared.Api;
34
using LrmCloud.Shared.DTOs;
45
using LrmCloud.Shared.DTOs.Projects;
@@ -12,10 +13,12 @@ namespace LrmCloud.Web.Services;
1213
public class ProjectService
1314
{
1415
private readonly HttpClient _httpClient;
16+
private readonly JsonSerializerOptions _jsonOptions;
1517

16-
public ProjectService(HttpClient httpClient)
18+
public ProjectService(HttpClient httpClient, JsonSerializerOptions jsonOptions)
1719
{
1820
_httpClient = httpClient;
21+
_jsonOptions = jsonOptions;
1922
}
2023

2124
public async Task<List<ProjectDto>> GetProjectsAsync(int? organizationId = null)
@@ -84,7 +87,7 @@ public async Task<ServiceResult<ProjectDto>> CreateProjectAsync(CreateProjectReq
8487
{
8588
try
8689
{
87-
var response = await _httpClient.PostAsJsonAsync("projects", request);
90+
var response = await _httpClient.PostAsJsonAsync("projects", request, _jsonOptions);
8891

8992
if (response.IsSuccessStatusCode)
9093
{
@@ -108,7 +111,7 @@ public async Task<ServiceResult<ProjectDto>> UpdateProjectAsync(int id, UpdatePr
108111
{
109112
try
110113
{
111-
var response = await _httpClient.PutAsJsonAsync($"projects/{id}", request);
114+
var response = await _httpClient.PutAsJsonAsync($"projects/{id}", request, _jsonOptions);
112115

113116
if (response.IsSuccessStatusCode)
114117
{
@@ -215,14 +218,40 @@ private static async Task<string> ReadErrorMessageAsync(HttpResponseMessage resp
215218
try
216219
{
217220
var content = await response.Content.ReadAsStringAsync();
218-
if (content.Contains("\"detail\""))
221+
var doc = JsonDocument.Parse(content);
222+
223+
// Check for "detail" (custom API error message)
224+
if (doc.RootElement.TryGetProperty("detail", out var detail))
225+
{
226+
return detail.GetString() ?? "An error occurred";
227+
}
228+
229+
// Check for "errors" (validation errors)
230+
if (doc.RootElement.TryGetProperty("errors", out var errors))
219231
{
220-
var problem = System.Text.Json.JsonDocument.Parse(content);
221-
if (problem.RootElement.TryGetProperty("detail", out var detail))
232+
var errorMessages = new List<string>();
233+
foreach (var field in errors.EnumerateObject())
222234
{
223-
return detail.GetString() ?? "An error occurred";
235+
if (field.Value.ValueKind == JsonValueKind.Array)
236+
{
237+
foreach (var msg in field.Value.EnumerateArray())
238+
{
239+
errorMessages.Add(msg.GetString() ?? field.Name);
240+
}
241+
}
242+
}
243+
if (errorMessages.Count > 0)
244+
{
245+
return string.Join(". ", errorMessages);
224246
}
225247
}
248+
249+
// Check for "title" (general error title)
250+
if (doc.RootElement.TryGetProperty("title", out var title))
251+
{
252+
return title.GetString() ?? "An error occurred";
253+
}
254+
226255
return content.Length < 200 ? content : "An error occurred";
227256
}
228257
catch

0 commit comments

Comments
 (0)