У меня есть следующий фрагмент кода, который отправляет запрос Http POST на сервер. Сервер возвращает ответ на запрос 400 Bad вместе с объектом ошибки в виде Json:
namespace MyApp.Shared.Dtos.Response
{
public class ErrorItem
{
public string Message { get; set; }
public string Tag { get; set; }
}
public class ErrorDto
{
public string Title { get; set; }
public List<ErrorItem> Errors { get; set; } = new();
}
}
namespace Accounting.Web.Services
{
public interface IHttpService
{
Task<T> Get<T>(string uri);
Task<T> Post<T>(string uri, object value, bool addBearerToken = false);
public ErrorDto Error { get; set; }
}
public class HttpService: IHttpService
{
private HttpClient _httpClient;
public ErrorDto Error { get; set; }
public HttpService(HttpClient httpClient)
{
_httpClient = httpClient;
_stateService = stateService;
}
public async Task<T> Post<T>(string uri, object value)
{
var request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = new StringContent(JsonSerializer.Serialize(value), Encoding.UTF8, "application/json");
return await sendRequest<T>(request, addBearerToken);
}
private async Task<T> sendRequest<T>(HttpRequestMessage request)
{
using var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
{
var result = await response.Content.ReadAsStringAsync();
Error = JsonSerializer.Deserialize<ErrorDto>(result);
//..
}
else
{
//..
}
}
}
}
Результат правильно получает следующий ответ от сервера в виде строки JSON:
{"title":"Неверное имя пользователя или пароль","ошибки":[]}
И я могу подтвердить, проверив результат var, он имеет указанное выше значение.
Однако, похоже, он не десериализуется в класс ErrorDto, как можно было бы ожидать: Ошибка = JsonSerializer.Deserialize (результат);
Но я просто не вижу проблем с кодом, вроде он должен работать.
*** ОБНОВЛЯТЬ ***
Код API моего сервера возвращает JSOn, используя тот же класс DTO (это общий класс), используя следующий код:
[HttpPost("authenticate")]
public ActionResult Authenticate(AuthenticateRequest loginRequest)
{
var auth = _userService.Authenticate(loginRequest);
ErrorDto error = new()
{
Title = "Username or password is incorrect"
};
if (auth.user == null || auth.token == null)
{
return BadRequest(error);
}
return Ok(auth.user.ConvertToDto(auth.token));
}
По умолчанию System.Text.Json
чувствителен к регистру. Есть несколько способов справиться с этим, например, предоставив соответствующий JsonSerializerOptions
:
var json = @"{""title"":""Username or password is incorrect"",""errors"":[]}";
var errorDto = JsonSerializer.Deserialize<ErrorDto>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
Или пометить свойства соответствующими JsonPropertyNameAttribute
:
public class ErrorItem
{
[JsonPropertyName("message")]
public string Message { get; set; }
[JsonPropertyName("tag")]
public string Tag { get; set; }
}
public class ErrorDto
{
[JsonPropertyName("title")]
public string Title { get; set; }
[JsonPropertyName("errors")]
public List<ErrorItem> Errors { get; set; } = new();
}
УПД
Из документа Как настроить имена и значения свойств с помощью System.Text.Json:
Примечание
В сети по умолчанию используется верблюжий регистр.
Если вы хотите переключиться с верблюжьего регистра на политику именования, используемую для DTO, вы можете сделать следующее:
builder.Services.AddControllers()
.AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null);
Причина @MusaffarPatel, поскольку в этом документе указано: «По умолчанию в Интернете используется верблюжий регистр».
Ах, конечно, но я не могу понять, почему она возвращается как нижняя строка в первую очередь из моего серверного API, который сериализует тот же класс для ответа. Я обновил свой вопрос, чтобы включить код API сервера.