Показать сообщение отдельно
Старый 29.12.2021, 15:20   #4  
DSPIC is offline
DSPIC
Боец
 
1,077 / 1234 (44) ++++++++
Регистрация: 11.04.2008
Давайте разбираться.

Цитата:
Сообщение от 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()));
        }
    }

Последний раз редактировалось DSPIC; 29.12.2021 в 15:25.
За это сообщение автора поблагодарили: sukhanchik (4), vmoskalenko (6).