AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 20.12.2016, 14:41   #1  
AlexeyS is offline
AlexeyS
Участник
 
404 / 339 (12) ++++++
Регистрация: 15.06.2004
Адрес: москва
AIF + Web Services + JSON
Приветствую!
Начал разбираться с AIF и web-сервисами в Ax2012 и прошу подсказать некоторые вещи.

Хочу настроить обмен данными со сторонним приложением посредством JSON
(мастер-данные, создание заказов, запрос остатков)

По умолчанию сервисы в аксапте используют SOAP+WSDL.
Мне, похоже, нужен RESTFul+JSON

Как понял, последовательность действий такая:
Создаем свой Custom Inbound AIF Service, адаптер вида HTTP.
Создаем класс контракта и класс сервиса
Нужно переписать класс web-сервиса, чтобы вместо WDSL он отдавал JSON (например так https://community.dynamics.com.nsatc.../f/33/t/126680)
Чтобы сервис принимал JSON нужно переписать класс контракта, чтобы он умел парсить JSON.
все верно, или есть варианты лучше?
Старый 20.12.2016, 15:25   #2  
Vadik is offline
Vadik
Модератор
Аватар для Vadik
Лучший по профессии 2017
Лучший по профессии 2015
 
3,631 / 1849 (69) ++++++++
Регистрация: 18.11.2002
Адрес: гражданин Москвы
Цитата:
Сообщение от AlexeyS Посмотреть сообщение
все верно, или есть варианты лучше?
JSON потому что это круто / модно / по каким-то еще причинам ? 100% нужен HTTP адаптер и соответственно дополнительная прослойка в виде IIS ? Есть хотя бы теоретическая вероятность научить приложение "на той стороне" работать с nettcp binding-ами ?
__________________
-ТСЯ или -ТЬСЯ ?
Старый 20.12.2016, 16:08   #3  
AlexeyS is offline
AlexeyS
Участник
 
404 / 339 (12) ++++++
Регистрация: 15.06.2004
Адрес: москва
Цитата:
Сообщение от Vadik Посмотреть сообщение
JSON потому что это круто / модно / по каким-то еще причинам ? 100% нужен HTTP адаптер и соответственно дополнительная прослойка в виде IIS ? Есть хотя бы теоретическая вероятность научить приложение "на той стороне" работать с nettcp binding-ами ?
предстоит интегрироваться с приложением на андроиде (еще не написанном) и сторонние разработчики очень хотят json.
HTTP адаптер это промежуточная DLL-ка к каждому сервису?

нашел интересное сообщение у Maxim Gorbunov "делал интеграцию на AIF, которая обменивалась JSON-сообщениями. И даже не так сильно пришлось допиливать AIF. Если б проект был на AX2012, то и вообще бы не пришлось ничего пилить"
Интеграция - использовать стандарт или писать на коленке ?
звучит очень интересно, но из конкретики пока нашел только в "Developing secure mobile apps for Microsoft Dynamics AX 2012. White Paper" описание:
creating a RESTful service by using WCF через AIF Windows Azure Service Bus Adapter
но пока непонятно ,что за зверушка этот Bus Adapter
upd: No it is not possible to install the service bus on a Windows Server 2012. The companion apps are connecting to the Azure servicebus online
поэтому эта шина не подойдет

Последний раз редактировалось AlexeyS; 20.12.2016 в 16:29.
Старый 20.12.2016, 20:29   #4  
Vadik is offline
Vadik
Модератор
Аватар для Vadik
Лучший по профессии 2017
Лучший по профессии 2015
 
3,631 / 1849 (69) ++++++++
Регистрация: 18.11.2002
Адрес: гражданин Москвы
Цитата:
Сообщение от AlexeyS Посмотреть сообщение
нашел интересное сообщение у Maxim Gorbunov "делал интеграцию на AIF, которая обменивалась JSON-сообщениями. И даже не так сильно пришлось допиливать AIF. Если б проект был на AX2012, то и вообще бы не пришлось ничего пилить"
ну тут наверное надо в идеале Максима саммонить, но он сильно занят сейчас, насколько я понимаю
__________________
-ТСЯ или -ТЬСЯ ?
Старый 09.02.2017, 15:43   #5  
Maxim Gorbunov is offline
Maxim Gorbunov
Administrator
Соотечественники
Лучший по профессии 2009
 
2,483 / 645 (26) +++++++
Регистрация: 27.11.2001
Адрес: Dubai, UAE
Цитата:
Сообщение от AlexeyS Посмотреть сообщение
Как понял, последовательность действий такая:
Создаем свой Custom Inbound AIF Service, адаптер вида HTTP.
Создаем класс контракта и класс сервиса
Нужно переписать класс web-сервиса, чтобы вместо WDSL он отдавал JSON (например так https://community.dynamics.com.nsatc.../f/33/t/126680)
Чтобы сервис принимал JSON нужно переписать класс контракта, чтобы он умел парсить JSON.
все верно, или есть варианты лучше?
Можно и так, но, как мне кажется, проще просто приделать transformation на inbound port. Я делал .NET трансформации, которые конвертировали JSON-сообщения в XML и передавали их дальше в AIF. Там (в inbound pipeline) уже делал XSLT, чтобы привести XML к схеме, которая в AIF используется.

Для конвертации JSON и XML я пользовался Newtonsoft Json.NET (http://www.newtonsoft.com/json). Сначала была идея стандартным дот-нетовским сериалайзером пользоваться, но для него надо все контракты явно прописать. С точки зрения контроля над разработкой так, наверное, правильнее, но решение менее гибким становится. В общем, смотрите сами.

Если есть ещё вопросы, задавайте. Помогу чем смогу
__________________
Not registered yet? Register here!
Have comments, questions, suggestions or anything else regarding our web site? Don't hesitate, send them to me
За это сообщение автора поблагодарили: AlexeyS (3), Logger (1), alex55 (1).
Старый 09.02.2017, 15:53   #6  
Maxim Gorbunov is offline
Maxim Gorbunov
Administrator
Соотечественники
Лучший по профессии 2009
 
2,483 / 645 (26) +++++++
Регистрация: 27.11.2001
Адрес: Dubai, UAE
Цитата:
Сообщение от AlexeyS Посмотреть сообщение
creating a RESTful service by using WCF через AIF Windows Azure Service Bus Adapter
Не совсем понял, о каком White Paper речь. Если про вот это - Developing Mobile Apps - насколько я понял, там идея в том, что предлагается написать на .NET промежуточный WCF сервис, у которого будет RESTful endpoint и который будет принимать сообщения, заворачивать их в SOAP-конверт и отправлять в AIF. В принципе, тоже вариант, но понятно, что администрировать это будет немного сложнее. Ну и, опять же, вопрос гибкости: расширять решение будет немного сложнее.
__________________
Not registered yet? Register here!
Have comments, questions, suggestions or anything else regarding our web site? Don't hesitate, send them to me
Старый 09.02.2017, 17:47   #7  
AlexeyS is offline
AlexeyS
Участник
 
404 / 339 (12) ++++++
Регистрация: 15.06.2004
Адрес: москва
Ага, спасибо. Для 4.0 сделал web-сервис, который принимает json и конвертирует его в XML с помощью Json.NET. Дальше передаю эту XML в аксапту через бизнес-коннектор, там обрабатываю и возвращаю результат в виде строки json. Можно возвращать и XML, но структура достаточно простая, чтобы этим не заморачиваться, плюс лишние конвертации повлияют на время отклика.
Насчет 12 пока думаю - использовать AIF или работать как с 4.0, пока склоняюсь к варианту со своим сервисом.
Старый 09.02.2017, 18:52   #8  
Maxim Gorbunov is offline
Maxim Gorbunov
Administrator
Соотечественники
Лучший по профессии 2009
 
2,483 / 645 (26) +++++++
Регистрация: 27.11.2001
Адрес: Dubai, UAE
Вот ещё посмотрите: https://github.com/ffilardi/axaptaapi/wiki

Это что-то вроде фреймворка для оборачивания аксаптовских SOAP-сервисов в RESTful интерфейсы.
__________________
Not registered yet? Register here!
Have comments, questions, suggestions or anything else regarding our web site? Don't hesitate, send them to me
За это сообщение автора поблагодарили: mazzy (2), Diman (1).
Старый 27.02.2017, 13:01   #9  
AlexeyS is offline
AlexeyS
Участник
 
404 / 339 (12) ++++++
Регистрация: 15.06.2004
Адрес: москва
оставлю тут, вдруг кому пригодится:

Business connector кэширует данные, если было изменение класса, то можно почистить кэш,
Код:
axp = new Microsoft.Dynamics.BusinessConnectorNet.Axapta();
axp.Logon(null, null, null, null);
axp.CallStaticClassMethod("SysFlushAOD", "doFlush");
обращение к сервису из аксапты, получение JSON и конвертация в XML
Код:
boolean getInfo()
{
    boolean                         ret;
    str                             url = "http://url.url";
    CLRObject                       clrCredential   = null;
    System.Net.NetworkCredential    credential      = null;
    CLRObject                       clro            = null;
    System.Net.HttpWebRequest       httpRequest     = null;
    System.Net.HttpWebResponse      httpResponse    = null;
    System.IO.Stream                stream          = null;
    System.IO.StreamReader          streamReader    = null;
    System.Xml.Linq.XNode           xnode           = null;
    System.Exception                clrException;
    str                             s;
    ;

    try
    {
        new InteropPermission(InteropKind::ClrInterop).assert();

        clrCredential = new System.Net.NetworkCredential();
        credential = clrCredential;
        credential.set_UserName("user_name");
        credential.set_Password("user_pwd");

        clro         = System.Net.WebRequest::Create(url);
        httpRequest  = clro;

        httpRequest.set_Credentials(credential);

        httpResponse = httpRequest.GetResponse();
        stream = httpResponse.GetResponseStream();
        streamReader = new System.IO.StreamReader(stream);

        s = streamReader.ReadToEnd();

        if (s == "null" || s == "false")
        {
            info("No info");
            ret = false;
        }
        else
        {
            xnode = Newtonsoft.Json.JsonConvert::DeserializeXNode(s, "Root");
            s = xNode.ToString();
            xmlDoc = new XMLDocument();
            xmlDoc.loadXml(s);

            CodeAccessPermission::revertAssert();
            ret = true;
        }
    }
    catch(Exception::CLRError)
    {
        clrException = CLRInterop::getLastException();

        if (clrException)
        {
            clrException = clrException.get_InnerException();
            if (clrException)
            {
                error(clrException.get_Message());
            }
        }

        ret = false;
    }
 
    return ret;
}
За это сообщение автора поблагодарили: Vadik (1), trud (2), Logger (10), Ace of Database (3).
Старый 05.07.2017, 15:25   #10  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Этот Newtonsoft.Json имеет проблемы при передаче из аксапты real типа. Т.е. всех суммовых значений.
Вот пример
X++:
static void Job3991_axforum(Args _args)
{
    GRD_JsonWriter      jsonWriter;
    real                r;
    System.Double       netDouble;
    System.Single       netSingle;
    System.Decimal      netDecimal;
    str                 ret;
    Newtonsoft.Json.Linq.JTokenWriter       writer;
    Newtonsoft.Json.Linq.JObject    jObject;
    ClrObject                       clrObject;
    System.Globalization.NumberFormatInfo numinf;
    ;

    r = 268.17;

    writer = new Newtonsoft.Json.Linq.JTokenWriter();
    writer.WriteStartObject();
    
    writer.WritePropertyName("params");
    writer.WriteStartObject();

    writer.WritePropertyName("VATAmount_xppReal");
    writer.WriteValue(r);

    writer.WritePropertyName("VATAmount_Row");
    writer.WriteRawValue("268.17");

    netDouble = r;
    writer.WritePropertyName("VATAmount_netDouble");
    writer.WriteValue(netDouble);

    netSingle = r;
    writer.WritePropertyName("VATAmount_netSingle");
    writer.WriteValue(netSingle);

    netDecimal = New System.Decimal(netDouble);
    writer.WritePropertyName("VATAmount_netDecimalViaDouble");
    writer.WriteValue(netDecimal);

    netDecimal = New System.Decimal(netSingle);
    writer.WritePropertyName("VATAmount_netDecimalViaSingle");
    writer.WriteValue(netDecimal);


    numinf = new System.Globalization.NumberFormatInfo();
    numinf.set_NumberDecimalSeparator(".");
    netDecimal = System.Decimal::Parse("268.17", numinf);
    info(CLRInterop::getAnyTypeForObject(netDecimal));
    writer.WritePropertyName("VATAmount_netDecimal");
    writer.WriteValue(netDecimal);

    writer.WriteEndObject();
    writer.WriteEndObject();
    
    clrObject = writer.get_Token();
    jObject = clrObject;
    ret = jObject.ToString();

    info(ret);

}
На выходе дает
Цитата:
{
"params": {
"VATAmount_xppReal": 268.16999999999996,
"VATAmount_Row": 268.17,
"VATAmount_netDouble": 268.16999999999996,
"VATAmount_netSingle": 268.16999999999996,
"VATAmount_netDecimalViaDouble": 268.17,
"VATAmount_netDecimalViaSingle": 268.17,
"VATAmount_netDecimal": 268.17
}
}
В общем караул. Явно где-то точность теряется так что целые копейки перескакивают в дробные.
Приходится данные через System.Decimal передавать. Или самим значение параметра в строку конвертировать и пихать туда через WriteRawValue

Последний раз редактировалось Logger; 05.07.2017 в 15:45.
Старый 05.07.2017, 16:39   #11  
Alex_KD is offline
Alex_KD
Участник
AxAssist
MCBMSS
Соотечественники
 
522 / 362 (14) ++++++
Регистрация: 06.07.2006
Адрес: Melbourne, Down Under
Я вот этот метод использую -
Write JSON with JsonTextWriter

real пишется так -

X++:
public void WriteDecimalField(str propName, real value)
{
    ;
    writer.WritePropertyName(propName);
    writer.WriteValue(value);
}
Завернул все в класс-обертку JSONWriter.
X++:
static void Job38(Args _args)
{
    JSONWriter writerWrapper = JSONWriter::construct();
    real           a = 123.567;
    
    writerWrapper.WriteStartObject();    
    writerWrapper.WriteDecimalField("Ax_real_", a);
    writerWrapper.WriteEndObject();    
    info(writerWrapper.getJson());
}
Результат -

PHP код:
{
  
"Ax_real_"123.567

Имейте ввиду что скорость в CIL примерно в 1000-10000 раз быстрее. В целом пишет ооочень быстро.
__________________
AxAssist 2012 - Productivity Tool for Dynamics AX 2012/2009/4.0/3.0
За это сообщение автора поблагодарили: Logger (10).
Старый 05.07.2017, 16:54   #12  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Обертка не должна влиять. У нас тоже была обертка. Я для форума пример выложил без обертки, чтобы проще понимать и воспроизводить баг.
Код выполняется под CIL ?
Возможно с этим связано.
writer в вашем случае это объект какого типа ?

В моем случае проблема была в том что писали 268.17 а выводилось 268.16999999999996
Хотя для других чисел было нормально.
Попробуйте вывести именно 268.17

Последний раз редактировалось Logger; 05.07.2017 в 17:07.
Старый 06.07.2017, 15:42   #13  
Товарищ ♂uatr is offline
Товарищ ♂uatr
Участник
Аватар для Товарищ ♂uatr
MCBMSS
 
265 / 808 (27) +++++++
Регистрация: 23.10.2012
Взял код из джоба "Job3991_axforum", не воспроизвелась проблема.
Возможно дело в версии dll'ки?
Старый 06.07.2017, 15:51   #14  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Проверю под 2012-й, вы ведь на 2012-й пробовали ?
Я проверял под 2009-й.
Старый 06.07.2017, 16:34   #15  
Товарищ ♂uatr is offline
Товарищ ♂uatr
Участник
Аватар для Товарищ ♂uatr
MCBMSS
 
265 / 808 (27) +++++++
Регистрация: 23.10.2012
Да, из под 6.2.3000.110, с dll для .Net 4.5 v10.0.3.21018
За это сообщение автора поблагодарили: Logger (3).
Теги
aif, ax2012, azure service bus, json, округление

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
daxdilip: How to: Configure Dynamics AX AIF Services to listen for SSL Requests (https) Blog bot DAX Blogs 0 23.01.2011 10:12
emeadaxsupport: What changes are required if we change the Business Connector Proxy used by AX 2009 Generated AIF Web services Blog bot DAX Blogs 0 29.03.2010 15:05
Channel9: Microsoft Dynamics AX 2009 AIF Web Services Screencast Blog bot DAX Blogs 0 17.06.2009 17:05
axStart: InfoPath with default AIF web services Blog bot DAX Blogs 1 15.05.2008 02:27
Pokluda: Outbound web service (AIF) Blog bot DAX Blogs 0 28.10.2006 17:43
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 12:09.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.