Показать сообщение отдельно
Старый 07.07.2020, 23:17   #4  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,273 / 3466 (122) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
D365FO: Использование веб-сервиса через JSON
Для JSON структура построения кода несколько иная. Нам необходимо подготовить строку текста в некотором формате, затем вызвать сервис, передав ему эту строку, после чего получить ответ также в виде строки и разобрать полученную строку.
Тем не менее, нам также нужно создать проект на C# типа Console Application (или любого типа, который может быть запущен напрямую пользователем)
Процедура аутенфикации такая же, поэтому также необходимо добавлять в проект ссылку на библиотеку Microsoft.IdentityModel.Clients.ActiveDirectory путем выполнения команды
Цитата:
Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory
в Package Manager Console
Строку можно готовить (сериализовать) и разбирать (десериализовать) как "ручками", так и при помощи библиотеки Newtonsoft.Json, которую аналогичным способом (как и Microsoft.IdentityModel.Clients.ActiveDirectory) можно добавить в Package Manager Console путем выполнения команды
Цитата:
Install-Package Newtonsoft.Json
Также в проект необходимо добавить из заготовок от Microsoft следующие файлы:
ClientConfiguration.cs (с правками по параметрам авторизации)
OAuthHelper.cs (без правок)

А теперь начинаются различия.
Для начала нам понадобится класс JsonUtil, который будет генерировать нам URL-адрес, добавляя в него группу сервисов, сам сервис и операции сервиса.
X++:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tutorial_ConsumeServiceJSON
{
    public class JsonUtil
    {
        public const string OAuthHeader = "Authorization";
        public static string GetJsonServiceGroupURL(string aosUriString, string serviceGroupName)
        {
            var serviceUriStringTemplate = "{0}/api/services/{1}";
            var serviceUriString = string.Format(serviceUriStringTemplate, aosUriString.TrimEnd('/'), serviceGroupName);
            return serviceUriString;
        }
        public static string GetJsonServiceNameURL(string aosUriString, string serviceGroupName, string serviceName)
        {
            var serviceUriStringTemplate = "{0}/{1}";
            var serviceUriString = string.Format(serviceUriStringTemplate, GetJsonServiceGroupURL(aosUriString, serviceGroupName), serviceName);
            return serviceUriString;
        }
        public static string GetJsonOperationURL(string aosUriString, string serviceGroupName, string serviceName, string functionName)
        {
            var serviceUriStringTemplate = "{0}/{1}";
            var serviceUriString = string.Format(serviceUriStringTemplate, GetJsonServiceNameURL(aosUriString, serviceGroupName, serviceName), functionName);
            return serviceUriString;
        }
    }
}
Далее, нам нужно:
1. Описать класс-контракт, описанный на X++, т.к. в отличие от SOAP - здесь не передаются объекты, а значит для получения карточки клиента - нам потребуется повторное описание полей карточки.
Это делается так:
X++:
    public class Tutorial_CustServiceContract
    {
        public string parmCustAccount { get; set; }
        [JsonProperty("parmCustAccountName")]
        public string custAccountName { get; set; }
        public string parmCustGroupId { get; set; }
    }
Здесь при помощи атрибута JsonProperty мы можем определять названия переменных, которые не соответствуют названиям переменных, приходящих из сервиса (из сервиса нам приходят parmCustAccountName, а мы не обязаны использовать внутри C# именно такое название. Зато если мы используем именно такое название, то мы не обязаны использовать атрибут JsonProperty)

2. Библиотека Newtonsoft.Json умеет сериализовать / десериализовать только классы, поэтому если нам надо передать в сервис обычное значение (например, код клиента), то чтобы вручную не формировать строку JSON - нужно создать классы, состоящие из одной этой переменной:
X++:
    public class ParmCustAccount
    {
        [JsonProperty("_custAccount")]
        public string custAccount { get; set; }
    }
    public class ParmCustGroupId
    {
        [JsonProperty("_custGroupId")]
        public string custGroupId { get; set; }
    }
3. При передаче строки JSON в сервис - необходимо устанавливать свойство SendChunked в true для корректной обработки символов в Юникоде.

В итоге у меня получилось 2 класса:
JsonServices, который вызывает веб-сервис
X++:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.IO;
using Newtonsoft.Json;
using AuthenticationUtility;

namespace Tutorial_ConsumeServiceJSON
{
    public class Tutorial_CustServiceContract
    {
        public string parmCustAccount { get; set; }
        [JsonProperty("parmCustAccountName")]
        public string custAccountName { get; set; }
        public string parmCustGroupId { get; set; }
    }
    public class ParmCustAccount
    {
        [JsonProperty("_custAccount")]
        public string custAccount { get; set; }
    }
    public class ParmCustGroupId
    {
        [JsonProperty("_custGroupId")]
        public string custGroupId { get; set; }
    }
    public class JsonServices
    {
        public const string serviceGroupName = "Tutorial_CustServiceGroup";
        public const string serviceName = "Tutorial_CustService";
        public const string getCustDetailName = "getCustDetail";
        public const string getCustListOfGroupName = "getCustListOfGroup";

        string aosUriString;
        string bearerKey;
        [JsonProperty("return")]
        public Tutorial_CustServiceContract[] serviceContracts { get; set; }
        [JsonProperty("return")]
        public Tutorial_CustServiceContract serviceContract { get; set; }
        public JsonServices()
        {
            aosUriString = ClientConfiguration.Default.ActiveDirectoryResource;
            bearerKey = OAuthHelper.GetAuthenticationHeader(true);
        }
        private HttpWebRequest CreateRequest(string _address)
        {
            HttpWebRequest webRequest;
            webRequest = (HttpWebRequest)HttpWebRequest.Create(_address);
            webRequest.Method = "POST";
            // the request will be empty.
            webRequest.ContentLength = 0;
            webRequest.Headers.Set(JsonUtil.OAuthHeader, bearerKey);
            return webRequest;
        }
        private string ReadJsonResponse(HttpWebRequest _request)
        {
            string jsonString;
            using (HttpWebResponse webResponse = (HttpWebResponse)_request.GetResponse())
            {
                using (Stream stream = webResponse.GetResponseStream())
                {
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        jsonString = reader.ReadToEnd();
                    }
                }
            }
            return jsonString;
        }
        public Tutorial_CustServiceContract getCustDetail(string _custAccount)
        {
            string operationURL = JsonUtil.GetJsonOperationURL(aosUriString, serviceGroupName, serviceName, getCustDetailName);

            ParmCustAccount parmCustAccount = new ParmCustAccount();
            parmCustAccount.custAccount = _custAccount;
            string jsonCustAccount = JsonConvert.SerializeObject(parmCustAccount);
            HttpWebRequest webRequest;
            webRequest = CreateRequest(operationURL);
            webRequest.SendChunked = true;
            using (Stream stream = webRequest.GetRequestStream())
            {
                using (StreamWriter writer = new StreamWriter(stream))
                {
                    writer.Write(jsonCustAccount);
                    writer.Flush();
                }
            }
            string jsonResponse = ReadJsonResponse(webRequest);
            serviceContract = JsonConvert.DeserializeObject<Tutorial_CustServiceContract>(jsonResponse);
            return serviceContract;
        }
        public Tutorial_CustServiceContract[] getCustListOfGroup(string _custGroupId)
        {
            string operationURL = JsonUtil.GetJsonOperationURL(aosUriString, serviceGroupName, serviceName, getCustListOfGroupName);

            ParmCustGroupId parmCustGroupId = new ParmCustGroupId();
            parmCustGroupId.custGroupId = _custGroupId;
            string jsonCustGroupId = JsonConvert.SerializeObject(parmCustGroupId);
            HttpWebRequest webRequest;
            webRequest = CreateRequest(operationURL);
            webRequest.SendChunked = true;
            using (Stream stream = webRequest.GetRequestStream())
            {
                using (StreamWriter writer = new StreamWriter(stream))
                {
                    writer.Write(jsonCustGroupId);
                    writer.Flush();
                }
            }
            string jsonResponse = ReadJsonResponse(webRequest);
            serviceContracts = JsonConvert.DeserializeObject<Tutorial_CustServiceContract[]>(jsonResponse);
            return serviceContracts;
        }
    }
}
Program, который вызывает JsonServices
X++:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.IO;
using AuthenticationUtility;

namespace Tutorial_ConsumeServiceJSON
{
    class Program
    {
        static void Main(string[] args)
        {
            JsonServices jsonServices = new JsonServices();
            Tutorial_CustServiceContract contract;
            Tutorial_CustServiceContract[] contracts;

            contract = jsonServices.getCustDetail("RUMF-000001");
            Console.WriteLine(string.Format("{0} | {1} | {2}", contract.parmCustAccount, contract.custAccountName, contract.parmCustGroupId));
            contracts = jsonServices.getCustListOfGroup("Орг");
            foreach (Tutorial_CustServiceContract iterator in contracts)
            {
                Console.WriteLine(string.Format("{0} | {1} | {2}", iterator.parmCustAccount, iterator.custAccountName, iterator.parmCustGroupId));
            }
            Console.ReadLine();
        }
    }
}
Соответственно, билдим, запускаем, смотрим.
Результат, как и в случае с SOAP должен быть таким же
Название: Снимок.PNG
Просмотров: 559

Размер: 24.8 Кб
__________________
Возможно сделать все. Вопрос времени

Последний раз редактировалось sukhanchik; 09.12.2020 в 08:56.