Показать сообщение отдельно
Старый 29.12.2021, 22:57   #5  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5788 (200) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Цитата:
Сообщение от 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 платформа занимается тем, что десериализует для вашего сервиса коллекцию объектов и заодно проверяет, что объекты в коллекции - нужного типа, а не абы что. По-моему, это всё в совокупности стоит того, чтобы добавить методу лишний атрибут.

Последний раз редактировалось gl00mie; 29.12.2021 в 23:28.