Давайте разбираться.
Цитата:
Сообщение от
gl00mie
Это называется "закат солнца вручную".
...
PS. Сама постановка задачи уже наводит на подозрения:
Зачем это, спрашивается, в D365FO делать кастомный сервис, который на входе получал бы JSON, а не нормальный типизированный контракт?..
Про закат вручную:
Тут не вручную, а помощью стандартного класса FormJsonSerializer (D365).
Во-вторых - задача, когда на вход извне впаривают сырой JSON (или XML) стоит сплошь и рядом: "Мы вам будем передавать XML\JSON строку и точка. Мы не можем переделать нашу систему под вашу, чтобы завязаться на ваш веб сервис. Или можем, но за большие деньги, где-то через года пол. Наши клиенты по всему миру, мы работаем только так".
А какие есть альтернативы? Чаще всего для jSON встречается ручной парсинг строк strScan, strFind и т.д. Изредка попадаются продвинутые выринты - используют Newton.JSon.dll. C XML немного проще - стандартный класс пробега по XML с большего освоили, но это всё-равно абсолютный хардкод.
Про аттрибут:
Класс
FormJsonSerializer понимает только
DataCollectionAttribute. Более того, для дата-контрактов с их parm* методами этот аттрибут идеально подходит (на входе один параметр с таким же типом что и на выходе).
AifCollectionTypeAttribute пришел из AX2012. Он больше подходит для описания сервис-операций, где может быть несколько входных параметров, разных типов, а на выходе что-то третье. Но в AX2012 других выриантов не было.
Для сравнения:
X++:
// D365:
[
DataMemberAttribute("Student list"),
DataCollectionAttribute(Types::Class, classStr(StudentInfoContract))
]
public List parmStudentList(List _studentList = studentList)
// ИЛИ AX2012:
[
DataMemberAttribute("Student list"),
AifCollectionTypeAttribute("return", Types::Class, classStr(StudentInfoContract)),
AifCollectionTypeAttribute("_studentList", Types::Class, classStr(StudentInfoContract))
]
public List parmStudentList(List _studentList = studentList)
Т.е.второй вариант избыточный для дата-контрактов имхо.
Единственное - не уверен, понимает ли сериализатор D365 этот атрибут при описании контрактов для веб-сервисов - не приходилось применять, но как бы must Have.
Цитата:
Сообщение от
mazzy
пробелы в названии...
Какие заботливо разложенные грабли.
В XML так нельзя. В jSON можно.
Претензия к автору блога у меня только одна: корее всего куски кода он где-то вырвал и не тестировал. Или спешил, промазал и недопроверил
X++:
while (enumerator.moveNext())
{
Newtonsoft.Json.Linq.JObject jObj = enumerator.current();
studentInfoContract = FormJsonSerializer::deserializeObject(classNum(StudentInfoContract),jObj.ToString());
str studentId, studentName;
studentId = studentInfoContract.parmStudentId();
studentName = studentInfoContract.parmStudentName();
Info(strFmt("Studnet # %1: %2", studentId, studentName));
}
естественно, вот на этом получит моментальный взлёт, пытаясь закастить аксаптовский класс в CLR тип.
X++:
Newtonsoft.Json.Linq.JObject jObj = enumerator.current();
Вообще не понятно, как это должно было работать. С другой стороны - юридически, он прикрылся "This posting is provided "AS IS" with no warranties, and confers no rights."
Наверное он так хотел сделать:
X++:
public static void main(Args _args)
{
StudentsContract studentsContract;
void addStudent(str _id, str _name)
{
StudentInfoContract student = new StudentInfoContract();
student.parmStudentId(_id);
student.parmStudentName(_name);
studentsContract.parmStudentList().addEnd(student);
}
studentsContract = new StudentsContract();
studentsContract.parmStudentList(new List(Types::Class));
addStudent("1", "First");
addStudent("2", "Second");
// Serialize
str jSon = FormJsonSerializer::serializeClass(studentsContract);
// Deserialize
studentsContract = FormJsonSerializer::deserializeObject(classNum(StudentsContract), jSon);
ListEnumerator enumerator = studentsContract.parmStudentList().getEnumerator();
while (enumerator.moveNext())
{
StudentInfoContract student = enumerator.current();
info(strFmt("Studnet # %1: %2", student.parmStudentId(), student.parmStudentName()));
}
}