Показать сообщение отдельно
Старый 07.07.2020, 16:49   #1  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,275 / 3476 (122) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
D365FO: Создание сервиса по шагам
Добрый день! Решил обновить информацию 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, если веб-сервис предполагает изменение данных в системе.
Название: SNAG_Program-0032.png
Просмотров: 915

Размер: 21.6 Кб

Название: SNAG_Program-0033.png
Просмотров: 914

Размер: 8.9 Кб

Название: SNAG_Program-0034.png
Просмотров: 916

Размер: 9.4 Кб

5. Сервис нужно включить в Service Group, которая будет публиковаться. Поэтому создаем Service Group Tutorial_CustServiceGroup, устанавливаем у нее свойство AutoDeploy = Yes (иначе она не опубликуется) и включаем в эту группу наш сервис Tutorial_CustService
Название: SNAG_Program-0035.png
Просмотров: 910

Размер: 25.0 Кб

Название: SNAG_Program-0036.png
Просмотров: 1155

Размер: 3.8 Кб

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
Задав в браузере в адресе такую строку мы получаем ответ
Нажмите на изображение для увеличения
Название: SNAG_Program-0037.png
Просмотров: 140
Размер:	71.1 Кб
ID:	12871
Такой ответ говорит нам, что сервис успешно развернут и можно им пользоваться.

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

Для 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/
__________________
Возможно сделать все. Вопрос времени

Последний раз редактировалось sukhanchik; 08.07.2020 в 00:16.
За это сообщение автора поблагодарили: raz (10), Logger (10), f18 (2), Stitch_MS (11), IvanS (1).