Я много боролся с этим, я нашел несколько вопросов, но ни один не смог ответить на мои потребности. Я постараюсь опубликовать лучший вопрос и некоторые вещи, которые я пробовал.
Вот такая ситуация: У меня есть APIGateway и WebApp. WebApp отправляет запросы POST на APIGateway, пока все хорошо. Я использую атрибут FromBody для отправки более крупных объектов, и это тоже было хорошо, пока я не представил интерфейсы :))
Вот код:
Веб-приложение:
public interface ICommand
{
Guid CorrelationId { get; set; }
Guid SocketId { get; set; }
}
public class Command : ICommand
{
public Command(Guid CorrelationId, Guid SocketId)
{
this.CorrelationId = CorrelationId;
this.SocketId = SocketId;
}
public Guid CorrelationId { get; set; } = new Guid();
public Guid SocketId { get; set; } = new Guid();
}
public interface IDocument
{
Guid Id { get; set; }
ulong Number { get; set; }
}
public class Document : IDocument
{
public Guid Id { get; set; } = new Guid();
public ulong Number { get; set; } = 0;
}
public interface ICreateDocumentCommand : ICommand
{
IDocument Document { get; set; }
}
public class CreateDocumentCommand : Command, ICreateDocumentCommand
{
public CreateDocumentCommand(IDocument Document, ICommand Command) : base(Command.CorrelationId, Command.SocketId)
{
this.Document = Document;
}
public IDocument Document { get; set; }
}
APIGateway:
[HttpPost]
public async Task<IActionResult> Create([FromBody]CreateDocumentCommand documentCommand)
{
if (documentCommand == null)
{
return StatusCode(403);
}
return Json(documentCommand.Document.Id);
}
Пример использования:
public class InventoryList : Document
{
public Guid WarehouseId { get; set; } = new Guid();
}
// Example document class
////////////////////////////////////////
// Example POST Request
ICommand command = new Command(messageId, socketId);
switch (item.GetType().Name)
{
case "InventoryList":
command = new CreateDocumentCommand((InventoryList)item, command);
break;
}
string result = await PostAsync($"{apiGatewayAddress}{item.GetType().BaseType.Name}/Create", command, accessToken);
Моя функция отправки POST:
public async Task<string> PostAsync<T>(string uri, T item, string authorizationToken = null, string authorizationMethod = "Bearer")
{
JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, uri);
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(item, typeof(T), jsonSerializerSettings), System.Text.Encoding.UTF8, "application/json");
return await _client.SendAsync(requestMessage).Result.Content.ReadAsStringAsync();
}
Как видите, я включил TypeNameHandling.All в настройки сериализации JSON, запрос отправляется и вызывается Create в APIGateway. Однако параметр documentCommand имеет значение NULL.
Я читал это:Asp.Net Core Post FromBody всегда равен нулю
Этот:Приведение интерфейсов для десериализации в JSON.NET
Пробовал всевозможные фокусы, создал новые конструкторы, пометил их [JSONConstructor], но безуспешно. Также я попытался изменить тип параметра метода APIGateway Cerate на ICreateDocumentCommand и снова получил ноль. Я искал некоторые уловки привязки моделей в Интернете, но не смог найти ничего для привязки с FromBody. Я также нашел какое-то решение, включая DI, но я ищу простое решение. Надеюсь, нам удастся его найти :)





Оказывается, передать интерфейсы или классы с интерфейсами внутри как JSON не так просто. Я добавил собственный JSONConverter, и теперь он работает!
@DougWilson Что-то пошло не так, и тогда я создал отдельные контроллеры и типы для разных типов документов. Как CreateDocumentCommand -> CreateInvoiceCommand, CreateSomeOtherDocumentCommand. И внутри этих классов есть документ соответствующего типа. Это было то, от чего я пытался убежать ... Во всяком случае, это работает.
Было бы здорово, если бы вы поделились своим пользовательским JsonConverter в своем ответе.