Добрый день! Решил обновить информацию
AX 2012 Создание сервиса по шагам но уже для D365FO.
Изменений не так много в части кода на Х++ и радикально много в части кода на C#.
Все проверялось на версии платформы Update35 (7.0.5644.35548) и продукта 10.0.11 (10.0.464.10002)
Итак, задача:
1. Получить по коду клиента его полное наименование и группу
2. Получить по группе клиентов перечень всех клиентов, входящих в эту группу. Карточка клиента в перечне определяется полями:
a. Код клиента (CustTable.AccountNum)
b. Полное наименование (CustTable.name())
c. Группа клиента (CustTable.CustGroup)
Начинаем.
1. Создаем класс Tutorial_CustServiceContract, который будет хранить нашу карточку клиента из трех полей с parm-методами доступа к них (public переменные, объявленные на уровне класса из C# недоступны. Однако в данном примере я сознательно сделал переменные класса public, чтобы из X++ можно было с ними работать напрямую, без использования parm-методов). Класс помечаем атрибутом DataContractAttribute, а методы – DataMemberAttribute.
X++:
/// <summary>
/// Класс-контракт для хранения данных для сервиса по клиентам
/// </summary>
// VSUH, 30.06.2020
[DataContractAttribute]
class Tutorial_CustServiceContract
{
public CustAccount custAccount;
public DirPartyName custAccountName;
public CustGroupId custGroupId;
[DataMemberAttribute]
public CustAccount parmCustAccount(CustAccount _custAccount = CustAccount)
{
custAccount = _custAccount;
return custAccount;
}
[DataMemberAttribute]
public DirPartyName parmCustAccountName(DirPartyName _custAccountName = custAccountName)
{
custAccountName = _custAccountName;
return custAccountName;
}
[DataMemberAttribute]
public CustGroupId parmCustGroupId(CustGroupId _custGroupId = custGroupId)
{
custGroupId = _custGroupId;
return custGroupId;
}
}
2. Создаем класс Tutorial_CustService, который будет вызываться при вызове нашего веб-сервиса. В нем будет 2 метода: getCustDetail для получения карточки клиента по коду клиента и getCustListOfGroup для получения списка карточек клиентов по коду группы клиента. Список оформляется через стандартный класс List, состоящий из экземпляров классов-карточек клиента. Метод getCustListOfGroup помечается атрибутом AifCollectionTypeAttribute, показывающим, что будет возвращена коллекция объектов, которую нужно будет перебирать циклом foreach
X++:
/// <summary>
/// Класс-сервис для вызова снаружи
/// </summary>
// VSUH, 30.06.2020
class Tutorial_CustService
{
/// <summary>
/// Получение деталей карточки клиента по коду клиента
/// </summary>
/// <param name = "_custAccount">
/// Код клиента
/// </param>
/// <returns>
/// Класс-контракт с деталями карточки клиента
/// </returns>
public Tutorial_CustServiceContract getCustDetail(CustAccount _custAccount)
{
CustTable custTable;
Tutorial_CustServiceContract contract;
custTable = CustTable::find(_custAccount);
contract = new Tutorial_CustServiceContract();
contract.custAccount = _custAccount;
contract.custAccountName = custTable.name();
contract.custGroupId = custTable.CustGroup;
return contract;
}
/// <summary>
/// Получение перечня клиентов из заданной группы
/// </summary>
/// <param name = "_custGroupId">
/// Код группы клиентов
/// </param>
/// <returns>
/// Список классов-контрактов с деталями найденных клиентов
/// </returns>
[AifCollectionTypeAttribute('return', Types::Class, classstr(Tutorial_CustServiceContract))]
public List getCustListOfGroup(CustGroupId _custGroupId)
{
CustTable custTable;
Tutorial_CustServiceContract contract;
List contractList;
contractList = new List(Types::Class);
while select custTable
where custTable.CustGroup == _custGroupId
{
contract = new Tutorial_CustServiceContract();
contract.custAccount = custTable.AccountNum;
contract.custAccountName = custTable.name();
contract.custGroupId = custTable.CustGroup;
contractList.addEnd(contract);
}
return contractList;
}
}
3. Создаем сервис Tutorial_CustService в узле Services и указываем у него свойства:
Class = Tutorial_CustService (связываем сервис с классом Tutorial_CustService)
External Name = Tutorial_LabCustService - под этим именем сервис будет доступен снаружи через SOAP-технологию.
4. Добавляем в сервис операции - наши методы getCustDetail и getCustListOfGroup. У обоих методов включаем свойство Enable Idempotence = Yes (это означает, что при повторном вызове этих методов с теми же параметрами будет выдан тот же результат. Пока не исследовал влияние этого свойства на функциональность работы веб-сервисов). Свойство Subscriber access level отвечает за необходимый доступ к операциям сервиса внешней системы. Я это свойство оставил, как Read по умолчанию, т.к. в моем примере не производится изменение данных. Логично это свойство изменить на Invoke, если веб-сервис предполагает изменение данных в системе.
5. Сервис нужно включить в Service Group, которая будет публиковаться. Поэтому создаем Service Group Tutorial_CustServiceGroup, устанавливаем у нее свойство AutoDeploy = Yes (иначе она не опубликуется) и включаем в эту группу наш сервис Tutorial_CustService
6. Делаем билд.
Собственно, всё. Х++-ная часть на этом закончилась

.
Веб-сервисы теперь доступны снаружи через технологию SOAP и технологию JSON. Технология SOAP предполагает, что потребитель веб-сервиса получает от него объекты и работает с этими объектами. Технология JSON предполагает, что потребитель веб-сервиса получает некую текстовую информацию, с которой сам разбирается (в т.ч. сам должен создавать у себя необходимые объекты, например - ту же карточку клиента). Поэтому JSON работает быстрее, но сложнее для программиста, а SOAP - удобнее для разработки.
Соответственно SOAP-сервис доступен по адресу https://<URL>/soap/services/Tutorial_CustServiceGroup, где <URL> - это URL нашей системы; на OneBox это usnconeboxax1aos.cloud.onebox.dynamics.com, а Tutorial_CustServiceGroup - название нашей Service Group
Задав в браузере в адресе такую строку мы получаем ответ

Такой ответ говорит нам, что сервис успешно развернут и можно им пользоваться.
JSON-сервис доступен по адресу https://<URL>/api/services/Tutorial_CustServiceGroup, где <URL> - это URL нашей системы; на OneBox это usnconeboxax1aos.cloud.onebox.dynamics.com, а Tutorial_CustServiceGroup - название нашей Service Group
Задав в браузере в адресе такую строку мы получаем ответ

Такой ответ говорит нам, что сервис успешно развернут и можно им пользоваться.
Для JSON можно получить перечень всех веб-сервисов просто по адресу https://<URL>/api/services/, а также можно получить формат данных конкретного сервиса https://<URL>/api/services/Tutorial_CustServiceGroup/Tutorial_CustService и каждой его операции (https://<URL>/api/services/Tutorial_CustServiceGroup/Tutorial_CustService/getCustDetail и https://<URL>/api/services/Tutorial_CustServiceGroup/Tutorial_CustService/getCustListOfGroup)
Официальные (от Microsoft) примеры-заготовки по использованию сервиса через SOAP / JSON расположены по адресу:
https://github.com/Microsoft/Dynamic...erviceSamples/