Хотите улучшить этот вопрос? Обновите вопрос так, чтобы он вписывался в тематику Stack Overflow на русском.
Закрыт 1 год назад.
Библиотека Json.Net поддерживает через рефлексию установку полей с private set, поэтому вполне работают оба варианта:
public class Abc1
{
public int Id { get; set; }
public string Title { get; set; }
}
public class Abc2
{
public Abc2(int id, string title)
{
Id = id;
Title = title;
}
public int Id { get; private set; }
public string Title { get; private set; }
}
void Main()
{
var request = new Abc1 { Id = 1, Title = "Test" };
Execute(request);
var request = new Abc2(1, "Test");
Execute(request);
}
private void Execute<T>(T request)
{
var requestSerialized = JsonConvert.SerializeObject(request);
var deserialized = JsonConvert.DeserializeObject<T>(requestSerialized);
request.Dump();
requestSerialized.Dump();
deserialized.Dump();
}
Однако, несмотря на то, что в asp.net core от версии 1.0 до версии 2.2 встроен json.net в качестве штатного обработчика json - невозможно использовать класссы без конструктора по умолчанию в контроллере:
[HttpPost]
public async Task<object> Update([FromBody] City.Update.Command command, CancellationToken cancellationToken)
{
var result = await this.Mediator.Send(command, cancellationToken);
return result;
}
В случае, если у Command нет конструктора по умолчанию, а есть только private set - мы получим null, поля не установятся.
Отчего так и как это можно исправить?
В asp.net core 3.0 можно будет использовать:
services.AddMvc().AddNewtonsoftJson();
Но я ещё не тестировал бету.
Команда:
using MediatR;
namespace Application.City.Update
{
public class Command : IRequest<CityData>
{
public Command(CityData city)
{
this.City = city;
}
public CityData City { get; private set; }
}
public class CityData
{
public CityData()
{
}
public CityData(City city)
{
this.Id = city.Id;
this.Title = city.Title;
}
public int Id { get; set; }
public string Title { get; set; }
public City ToEntity()
{
return new City
{
Id = this.Id,
Title = this.Title,
};
}
}
}
Если что — это ответ на вопрос, а не дополнение к ответу. :)
В общем, похоже у меня не совсем точное понимание, что именно понимается под тем, как Json.Net обрабатывает private set. Он в принципе это делает, да, но как только речь заходит о составных объектах — начинаются нюансы.
Вот более расширенный пример, чем в вопросе:
public class Abc1
{
public int Id { get; set; }
public string Title { get; set; }
public DataDto1 Data { get; set; }
}
public class DataDto2
{
public DataDto2(string noteA, string noteB, string myProperty)
{
this.NoteA = noteA;
this.NoteB = noteB;
this.Ano = new AnotherDto2(myProperty);
}
public string NoteA { get; private set; }
public string NoteB { get; private set; }
public AnotherDto2 Ano { get; set; }
}
public class DataDto1
{
public string NoteA { get; set; }
public string NoteB { get; set; }
public AnotherDto1 Ano { get; set; }
}
public class AnotherDto2
{
public AnotherDto2(string myProperty)
{
MyProperty = myProperty;
}
public string MyProperty { get; private set; }
}
public class AnotherDto1
{
public string MyProperty { get; set; }
}
void Main()
{
var request = new Abc1 { Id = 1, Title = "Test", Data = new DataDto1 { NoteA = "tA", NoteB = "tB", Ano = new AnotherDto1 { MyProperty = "myPr"} } };
Execute(request);
var request = new Abc2(1, "Test", "tA", "tB", "myPr");
Execute(request);
}
Пока всё работает:
Однако, если на классе DataDto2 поменять определение составного свойства — то оно не установится:
public AnotherDto2 Ano { get; private set; }
Аналогично — если объявить private set на самом верхнем уровне для класса, то всё по цепочке будет null.
При этом примитивные типы на верхнем уровне ничуть не реагируют на смену видимости поля.
Итого, с учётом того, что у меня CityData - это плоская Dto всегда состаящая только из примитивных типов (int, string, DateTime) можно выкрутиться следующим образом:
[HttpPost]
public async Task<object> Update([FromBody] City.Update.CityData data, CancellationToken cancellationToken)
{
var command = City.Update.Command(data);
var result = await this.Mediator.Send(command, cancellationToken);
return result;
}
Команду тогда можно сделать полностью get only:
public class Command : IRequest<CityData>
{
public Command(CityData city)
{
this.City = city;
}
public CityData City { get; }
}
А для CityData убрать конструктор и проставить все поля в private set:
public class CityData
{
public CityData(City city)
{
this.Id = city.Id;
this.Title = city.Title;
}
public int Id { get; private set; }
public string Title { get; private set; }
public City ToEntity()
{
return new City
{
Id = this.Id,
Title = this.Title,
};
}
}
Update. Альтернативно
Если проставить атрибут - то сериализация снова подхватывается:
[JsonProperty]
public AnotherDto2 Ano { get; private set; }
Update2 Спасибо @PavelMayorov за ещё один хороший вариант решения задачи: [JsonConstructorAttribute]
(документация)
Update3 Спасибо за помощь @Grundy, который первым обратил внимание на то, что приведённый код должен десериализоваться. Действительно, пример в вопросе не является абсолютно точной копией того кода, который я запускал, при этом взгляд был замылен и я не рассмотрел мелких отличий, которые в итоге повлияли на иной ответ.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Имеется селект для отчета на MySQLОтчет буду публиковать на SRSS
Есть панель управления которая находится на поддомене dashboardsite
1) Есть база данных в ней есть поля id title foregin 2) в title перечислены отечественные машины и иностранные 3) иностранные машины записаны в таблице...