Цитата:
Сообщение от
DSPIC
Тут не вручную, а помощью стандартного класса FormJsonSerializer (D365).
Имя стандартного класса как бы намекает, что он задумывался больше для форм, чем для сервисов
Цитата:
Сообщение от
DSPIC
Во-вторых - задача, когда на вход извне впаривают сырой JSON (или XML) стоит сплошь и рядом: "Мы вам будем передавать XML\JSON строку и точка. Мы не можем переделать нашу систему под вашу, чтобы завязаться на ваш веб сервис.".
Наверно, так тоже бывает, но в данном случае автор сам же пишет: я решил сделать сервис, вот его контракт, в контракте есть коллекция классов. Он не пишет, что парсит чей-то чужой JSON - напротив, он получает на вход именно тот контракт, который заказывал, только "недодесериализованный", полусырой, так сказать. Скажу больше: кастомные сервисы в D365FO доступны извне и как REST (с JSON-ом на входе), и как SOAP-сервисы (c XML на входе), но из-за того, что автор использовал
не тот атрибут в контракте, он и для SOAP-варианта своего сервиса получил полусырой WSDL, в котором коллекция классов будет представлена как просто абстрактный массив не пойми чего. Использованием неправильного атрибута автор и себе лишнюю работу создал, и клиентам, которые попытаются WSDL сервиса посмотреть, проблем подкинул.
Цитата:
Сообщение от
DSPIC
Про аттрибут:
Класс FormJsonSerializer понимает только DataCollectionAttribute. Более того, для дата-контрактов с их parm* методами этот аттрибут идеально подходит (на входе один параметр с таким же типом что и на выходе).
Идеально подходит для любителей ручного разбора JSON и полусырых WSDL-ей
Цитата:
Сообщение от
DSPIC
AifCollectionTypeAttribute пришел из AX2012.
Какая разница, откуда пришел атрибут? DataContractAttribute тоже был в AX2012, и что, может, на этом основании его не использовать?
Приложение D365FO на 90-95% - это приложение AX2012 R3, и если какие-то вещи из AX2012 продолжают успешно работать в D365FO, а альтернатива им - закат солнца вручную, то какой смысл от них отказываться?
Цитата:
Сообщение от
DSPIC
Он больше подходит для описания сервис-операций, где может быть несколько входных параметров, разных типов, а на выходе что-то третье.
Либо на входе сервисного метода - коллекция одних типов, а на выходе - коллекция других типов.
Цитата:
Сообщение от
DSPIC
Но в AX2012 других выриантов не было.
Во-первых, были альтернативы, посмотрите хотя бы на полёт фантазии в FormLetterContract:
X++:
[DataMemberAttribute]
public str parmDataSourceRecordsPacked(str _dataSourceRecordsPacked = '')
{
if (prmIsDefault(_dataSourceRecordsPacked))
{
return SysOperationHelper::base64Encode(this.parmDataSourceRecordMapPacked());
}
return SysOperationHelper::base64Encode(this.parmDataSourceRecordMapPacked(SysOperationHelper::base64Decode(_dataSourceRecordsPacked)));
}
Мощно?!
Во-вторых, никто не мешал даже в AX2012 определить свой класс атрибута и парсить вручную что угодно аналогично тому, как это теперь делает FormJsonSerializer.
Цитата:
Сообщение от
DSPIC
Для сравнения:
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)
Мы же помним, что кастомные сервисы в D365FO доступны извне одновременно и как REST, и как SOAP-сервисы, причем в REST метаданные, мягко говоря, победнее. Сделаем в контракте два поля, одно - studentList - с атрибутом DataCollection, а другое - studentListAif - с атрибутом AifCollectionType. И посмотрим теперь, как такие поля в контракте сервиса D365FO выглядят в WSDL:
PHP код:
<xs:complexType name="StudentsContract">
<xs:complexContent mixed="false">
<xs:extension xmlns:q8="http://schemas.datacontract.org/2004/07/Microsoft.Dynamics.Ax.Xpp" base="q8:XppObjectBase">
<xs:sequence>
<xs:element xmlns:q9="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
minOccurs="0" name="StudentList"
nillable="true" type="q9:ArrayOfanyType"/>
<xs:element minOccurs="0" name="StudentListAif"
nillable="true" type="tns:ArrayOfStudentInfoContract"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="StudentsContract" nillable="true" type="tns:StudentsContract"/>
<xs:complexType name="ArrayOfStudentInfoContract">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="StudentInfoContract" nillable="true" type="tns:StudentInfoContract"/>
</xs:sequence>
</xs:complexType>
<xs:element name="ArrayOfStudentInfoContract" nillable="true" type="tns:ArrayOfStudentInfoContract"/>
<xs:complexType name="StudentInfoContract">
<xs:complexContent mixed="false">
<xs:extension xmlns:q10="http://schemas.datacontract.org/2004/07/Microsoft.Dynamics.Ax.Xpp" base="q10:XppObjectBase">
<xs:sequence>
<xs:element minOccurs="0" name="StudentId" nillable="true" type="xs:string"/>
<xs:element minOccurs="0" name="StudentName" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Видим, что для DataCollection мы получили StudentList в виде ArrayOfanyType, без какой-либо дальнейшей детализации.
А для AifCollectionType мы получили StudentListAif в виде ArrayOfStudentInfoContract с полной разблюдовкой: мы видим в WSDL и сам StudentInfoContract, и то, что он состоит из двух строковых полей: StudentId и StudentName. И повторюсь: для AifCollectionType платформа занимается тем, что десериализует для вашего сервиса коллекцию объектов и заодно проверяет, что объекты в коллекции - нужного типа, а не абы что. По-моему, это всё в совокупности стоит того, чтобы добавить методу лишний атрибут.