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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 14.02.2017, 09:18   #1  
Avalon is offline
Avalon
Участник
 
11 / 10 (1) +
Регистрация: 28.10.2009
runbuf на сервере
Всем привет.
Есть одна не большая задача. Я нашёл один путь её решения, но возможно такую же задачу кто-то решал и нашёл другой путь.
Итак, у нас есть несколько сайтов, возвращающих рублёвый курс валюты:
юань - XXX.XXX.XXX.XXX:8081
евро - XXX.XXX.XXX.XXX:8082
доллар - XXX.XXX.XXX.XXX:8083
У каждого сайт есть описанный WSDL с одинаковой функцией getCurrency. Все эти сайты не "наши" и попросить "их" сделать как-то по другому - нельзя. Один раз в сутки, карета превращается в тыкву и меняет свой адрес на YYY.YYY.YYY.YYY и каждый раз этот ip новый.
Сама задача - хочется автоматически в серверном режиме менять настройки данных адресов.
Для начала создадим описание наших WSDL:
Нам присылают текстовый файл, с текущими IP, обходим его в цикле и создаём ServiceReference вот такими строчками:
X++:
SysReference::createServiceReference('CurrencyU', 'XXX.XXX.XXX.XXX:8081?WSDL', 'CurrencyU', 'юань');
SysReference::createServiceReference('CurrencyE', 'XXX.XXX.XXX.XXX:8082?WSDL', 'CurrencyE', 'евро');
SysReference::createServiceReference('CurrencyD', 'XXX.XXX.XXX.XXX:8083?WSDL', 'CurrencyD', 'доллар');
В результате, в AOT в разделе References, появятся следующие объекты: CurrencyU, CurrencyE, CurrencyD.

Теперь мы сможем к ним обратиться таким кодом:
X++:
CurrencyU.AxCurrencyTypeClient webService = new CurrencyU.AxCurrencyTypeClient("AxCurrencySoap");
currentCurrency = webService.getCurrency();
Всё отлично, текущий курс получили. Теперь мы хотим это дело как-то автоматизировать. Если написать вот такой код в job:
X++:
string command = '%1 webService = %1("AxCurrencySoap");';
currentCurrency = webService.getCurrency();
runBuf(command, 'CurrencyU.AxCurrencyTypeClient');
То она работает, всё замечательно. Но, как мы знаем, job выполняется на клиенте, если же поместить это на сервер, то получим ошибку: Unable to compile. Круто, интересно почему. Пихаем наш код в xppCompiler и видим ошибку: У таблицы не существует поля. Строчку не пишет, но однозначно ругается на CurrencyU.AxCurrencyTypeClient, даже если его записать жёстко. Вот тут и наступает беда - нам нужно работать в серверном режиме, а тут такой облом и беда вся в том, что объект составной. В других случаях всё работает.

В результате написал код, который в X++ изменяет метод возврата объектов, т.е. есть класс Currency, и у него есть метод getReference, который генерируется автоматически, по приблизительно следующему коду:

X++:
classBuild  =   new ClassBuild(classStr(Currency), true);
    getServiceReference =
        '//  Внимание! Данный метод генерируется автоматически Currency::buildReferences()'                           +   '\n'    +
        'public static server object getServiceReference(str _referenceName)'                                                   +   '\n'    +
        '{'                                                                                                                     +   '\n'    +
        '    Object  object;'                                                                                                   +   '\n'    +
        '    ;'                                                                                                                 +   '\n';
        while select currencies
        {
            getServiceReference +=
        '        case    "' +   currencies.ServiceReferenceName  +'"   :'                                                    +   '\n'    +
        '            object  =   new '  +   currencies.ServiceReferenceName  +   '.AxCurrencyPortTypeClient("AxCurrencySoap");'    +   '\n'    +
        '            break;'                                                                                                    +   '\n';
        }
        getServiceReference +=
        '    }'                                                                                                                 +   '\n';
    }
    getServiceReference +=
        '    return  object;'                                                                                                   +   '\n'    +
        '}';
    classBuild.overrideMethod('getServiceReference', getServiceReference);
Собственно вопрос - есть еще какие-нибудь способы обойти данную ошибку в серверной версии? Я думаю что это баг, т.к. в клиентском режиме он нормально проглатывает весь код.
P.S. Это только общий смысл и код приведён лишь частично.

Последний раз редактировалось Avalon; 14.02.2017 в 09:26.
Старый 14.02.2017, 09:54   #2  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
вы бы указали версию аксапты.
судя по тому, что на клиенте выполняется, а на сервере нет, то у вас меньше акс2012.

начиная с акс4.0 ввели Secure API и специальные permissions на выполнение некоторых операций в коде.
в частности, для выполнения runbuf требуется явно получить ExecutePermission в CodeAccessPermission

см:
https://msdn.microsoft.com/en-us/library/aa656300.aspx
https://msdn.microsoft.com/en-us/lib...ermission.aspx
https://msdn.microsoft.com/en-us/lib...ermission.aspx
https://msdn.microsoft.com/en-us/library/aa852189.aspx
Старый 14.02.2017, 10:01   #3  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
и еще.
не создавайте строки в таком стиле - у вас сборщик мусора с ума сходит от такого.
Цитата:
Сообщение от Avalon Посмотреть сообщение
X++:
    getServiceReference =
        '//  Внимание! Данный метод генерируется автоматически Currency::buildReferences()'                           +   '\n'    +
        'public static server object getServiceReference(str _referenceName)'                                                   +   '\n'    +
...
в аксапте есть режим литеральной строки

X++:
    getServiceReference =
        @'//  Внимание! Данный метод генерируется автоматически Currency::buildReferences()
public static server object getServiceReference(str _referenceName)
...
...
...';
также используйте strfmt() вместо плюсов...
Помогите найти: Сравнение производительности различных операндов при конкатенации строк
Старый 14.02.2017, 10:15   #4  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
и еще... извините.

это вам только кажется, что вы сделали универсальное решение, которое позволяет работать с любыми строчками.
Цитата:
Сообщение от Avalon Посмотреть сообщение
X++:
        '            object  =   new '  +   currencies.ServiceReferenceName  +   '.AxCurrencyPortTypeClient("AxCurrencySoap");'    +   '\n'    +
на самом деле у вас доступны только те значения, для которых есть классы в коде.
если в коде только 3 (три) класса, то другие строчки приведут к ошибке в runtime.

другими словами, вы нисколько не приблизились к универсальности.
зато:
= перевели все ошибки в runtime
= сильно затруднили диагностику ошибок (теперь будет выдаваться ошибка компиляции вместо ошибки "неправильная строка")
= сильно затруднили себе жизнь с runbuf, правами и обвязкой

для таких задач делают семейство классов с construct
в construct передают параметр и явно пишут что он может создавать.
когда добавляется новый класс наследник, программист должен будет расширить construct в базовом классе.

это паттерн, который используется повсеместно во всей аксапте.
поищите в коде примеры
Старый 14.02.2017, 11:36   #5  
MazZzDaI is offline
MazZzDaI
Участник
Аватар для MazZzDaI
 
44 / 35 (2) +++
Регистрация: 19.09.2013
1. XppCompiler - не может в CIL.
2. Делайте DLL на C#, в которой используйте ConfigurationChannelFactory, - ей можно отдать endpoint address c нужным вам URL'ом (IP)
За это сообщение автора поблагодарили: Logger (5).
Старый 14.02.2017, 12:14   #6  
Avalon is offline
Avalon
Участник
 
11 / 10 (1) +
Регистрация: 28.10.2009
Цитата:
Сообщение от mazzy Посмотреть сообщение
вы бы указали версию аксапты.
судя по тому, что на клиенте выполняется, а на сервере нет, то у вас меньше акс2012.

начиная с акс4.0 ввели Secure API и специальные permissions на выполнение некоторых операций в коде.
в частности, для выполнения runbuf требуется явно получить ExecutePermission в CodeAccessPermission
AX 2009. Пермишены специально не писал, они в примере не нужны, так они есть и отрабатывают, с этим всё в порядке.
Старый 14.02.2017, 12:17   #7  
Avalon is offline
Avalon
Участник
 
11 / 10 (1) +
Регистрация: 28.10.2009
Цитата:
Сообщение от mazzy Посмотреть сообщение
и еще.
не создавайте строки в таком стиле - у вас сборщик мусора с ума сходит от такого.

в аксапте есть режим литеральной строки

также используйте strfmt() вместо плюсов...
Спасибо, это я всё знаю, но по факту, данный код будет выполняться 1-2 раза в году (а может и меньше), а мне в данном случае мне удобней писать именно так.
Старый 14.02.2017, 12:21   #8  
Avalon is offline
Avalon
Участник
 
11 / 10 (1) +
Регистрация: 28.10.2009
Цитата:
Сообщение от mazzy Посмотреть сообщение
и еще... извините.

это вам только кажется, что вы сделали универсальное решение, которое позволяет работать с любыми строчками.


на самом деле у вас доступны только те значения, для которых есть классы в коде.
если в коде только 3 (три) класса, то другие строчки приведут к ошибке в runtime.

другими словами, вы нисколько не приблизились к универсальности.
зато:
= перевели все ошибки в runtime
= сильно затруднили диагностику ошибок (теперь будет выдаваться ошибка компиляции вместо ошибки "неправильная строка")
= сильно затруднили себе жизнь с runbuf, правами и обвязкой

для таких задач делают семейство классов с construct
в construct передают параметр и явно пишут что он может создавать.
когда добавляется новый класс наследник, программист должен будет расширить construct в базовом классе.

это паттерн, который используется повсеместно во всей аксапте.
поищите в коде примеры
Извините, но вы совсем не поняли что я делаю. construct можно использовать только тогда, когда известны объекты, а у меня объекты меняются, создаются новые. И этот construct у меня генерируется налету, чтобы не утруждать 'пользователей'.
Старый 14.02.2017, 12:22   #9  
Avalon is offline
Avalon
Участник
 
11 / 10 (1) +
Регистрация: 28.10.2009
Цитата:
Сообщение от MazZzDaI Посмотреть сообщение
1. XppCompiler - не может в CIL.
2. Делайте DLL на C#, в которой используйте ConfigurationChannelFactory, - ей можно отдать endpoint address c нужным вам URL'ом (IP)
Спасибо за интерес к данной теме, хотелось бы узнать есть ли другие решения в рамках Ax.
Старый 14.02.2017, 12:45   #10  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Avalon Посмотреть сообщение
Извините, но вы совсем не поняли что я делаю.
Именно.
Уверен, мало кто поймет, что вы делаете.

но хозяин - барин.

а задача - вполне типовая, сводится к управлению локальными записями в dns-кэше.
Старый 14.02.2017, 13:03   #11  
fed is offline
fed
Moderator
Аватар для fed
Ex AND Project
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
2,909 / 5730 (197) ++++++++++
Регистрация: 13.03.2002
Адрес: Hüfingen,DE
Есть еще более примитивное решение:
1. В \windows\system32\driver\etc\hosts добавляем строчку вида "ourWFCServer XXX.XXX.XXX.XXX" (Где xxx.. - текущий адрес сервера на момент генерации).
2. генерируем Service Reference для адреса ourWCFServer.
3. Пишем отдельный батч, который при получении нужного файла с адресами, правит этот самый hosts-файл.
За это сообщение автора поблагодарили: MazZzDaI (1).
Старый 14.02.2017, 13:26   #12  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
647 / 350 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Не поленитесь, создайте класс-обертку для каждого вашего класса CurrencyU и пр. Сделайте их наследниками общего класса с вашей функцией getCurrency() и обойдитесь без runBuf().
Цитата:
Сообщение от Avalon Посмотреть сообщение
Спасибо, это я всё знаю, но по факту, данный код будет выполняться 1-2 раза в году (а может и меньше), а мне в данном случае мне удобней писать именно так.
Это путь к одиночеству. Тем более, что если вы все и так знаете, но вам "удобнее" по-другому.
Использование strFmt() - это не просто еще один способ, это общемировая практика. Речь идет даже не о производительности, а о понимании вас другими разработчиками. И в вашем случае не важно сколько раз в году этот код будет выполняться, а то, сколько людей будет модифицировать ваш код и поносить ваше имя так, что уши гореть будут.
__________________
// no comments
Старый 14.02.2017, 14:12   #13  
Avalon is offline
Avalon
Участник
 
11 / 10 (1) +
Регистрация: 28.10.2009
Цитата:
Сообщение от fed Посмотреть сообщение
Есть еще более примитивное решение:
1. В \windows\system32\driver\etc\hosts добавляем строчку вида "ourWFCServer XXX.XXX.XXX.XXX" (Где xxx.. - текущий адрес сервера на момент генерации).
2. генерируем Service Reference для адреса ourWCFServer.
3. Пишем отдельный батч, который при получении нужного файла с адресами, правит этот самый hosts-файл.
Так то да, но проблема немного в другом. Проблема в том, что объекты в Ax создаются динамически, т.е. при создании валюты, появляется новый объект в AOT\References и хоть этот объект имеет однотипные свойства, но заранее он неизвестен. Вся задача написать общую обёртку для вызова. Если бы серверный runBuf мог это делать с составными типами данных, то проблем не было бы никаких, просто создал строчку и подставил в неё имя объекта.
Старый 14.02.2017, 14:14   #14  
Avalon is offline
Avalon
Участник
 
11 / 10 (1) +
Регистрация: 28.10.2009
Цитата:
Сообщение от dech Посмотреть сообщение
Не поленитесь, создайте класс-обертку для каждого вашего класса CurrencyU и пр. Сделайте их наследниками общего класса с вашей функцией getCurrency() и обойдитесь без runBuf().

Это путь к одиночеству. Тем более, что если вы все и так знаете, но вам "удобнее" по-другому.
Использование strFmt() - это не просто еще один способ, это общемировая практика. Речь идет даже не о производительности, а о понимании вас другими разработчиками. И в вашем случае не важно сколько раз в году этот код будет выполняться, а то, сколько людей будет модифицировать ваш код и поносить ваше имя так, что уши гореть будут.
Именно это я и пытаюсь сделать с заранее неизвестными объектами. Объекты (валюты) создаёт пользователь, который не умеет и не имеет прав редактировать код. Так что лень в данном случае не причём.
Старый 14.02.2017, 14:22   #15  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Avalon Посмотреть сообщение
Проблема в том, что объекты в Ax создаются динамически, т.е. при создании валюты, появляется новый объект в AOT\References и хоть этот объект имеет однотипные свойства, но заранее он неизвестен.
Здесь вы ошибаетесь.
Нет здесь неизвестных объектов и не нужно здесь динамического программирования.
Но опять же: хозяин - барин.
Старый 14.02.2017, 14:23   #16  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Avalon Посмотреть сообщение
Объекты (валюты) создаёт пользователь
Ни один отдельно взятый человек-пользователь СОЗДАВАТЬ валюты не может. ))))
Валют на всем земном шаре - конечное количество. Мало того, достаточно небольшое количество.
За это сообщение автора поблагодарили: dech (2).
Старый 15.02.2017, 08:01   #17  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
647 / 350 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Изначальная интерпретация задачи:
Цитата:
Сообщение от Avalon Посмотреть сообщение
Итак, у нас есть несколько сайтов, возвращающих рублёвый курс валюты.
Все эти сайты не "наши" и попросить "их" сделать как-то по другому - нельзя.
Получается, что "чужой" программист пишет веб-сервисы по каждой валюте, а у вас в наличии список с ip-адресами и вы дергаете нужную валюту, чтобы получить курс.
Цитата:
Сообщение от Avalon Посмотреть сообщение
Объекты (валюты) создаёт пользователь, который не умеет и не имеет прав редактировать код.
Тогда какого черта вы подпрягаете пользователей, чтобы
  • делать лишние телодвижения для получения курса валюты
  • ставить под угрозу всю систему, АОС может и не упадет, но Runtime error вы получите если что-то вдруг поменяется.
Ну и раз уж у вас все динамическое, вы бы хоть хранили данные в таблицах
__________________
// no comments
Старый 15.02.2017, 08:12   #18  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от dech Посмотреть сообщение
Тогда какого черта вы подпрягаете пользователей, чтобы
скорее всего, программисты на этой стороне (свои программисты) не знают измененные ip-адреса
скорее всего, смена ip-адресов является что-то вроде защиты платного сервиса - где-то в платной области есть постоянный адрес и редирект на новый ip-адрес.
скорее всего, ответственные пользователи не захотели оплачивать этот платный сервис, а напрягли "своих" программистов.
скорее всего, "свои" программисты в качестве своеобразной мести заставили пользователей вводить адреса, а пользователи в отместку "присылают текстовый файл" непонятного формата.

Цитата:
Сообщение от dech Посмотреть сообщение
а у вас в наличии список.
вот! ключевое слово "список". можно даже сказать - постоянный список.
элементы в этом списке далеко не произвольные. элементы в этот список добавляются очень редко. добавление в этот список связано с обязательным созданием нового класса в аксапте.

переменной частью в этом списке является только адреса.

динамическое программирование для такой задачи не нужно.
Скрипач не нужен, Дядя Вова.

Последний раз редактировалось mazzy; 15.02.2017 в 08:15.
Старый 15.02.2017, 09:10   #19  
Avalon is offline
Avalon
Участник
 
11 / 10 (1) +
Регистрация: 28.10.2009
Собственно, задача вообще к валюте никакого отношения не имеет, это был лишь завуалированный пример. Всем проще прицепиться к тому, что "фары не протёр", вместо того, чтобы понять почему двигатель не заводится. В любом случае всем спасибо, видимо других решений просто нет.
Старый 15.02.2017, 09:25   #20  
MazZzDaI is offline
MazZzDaI
Участник
Аватар для MazZzDaI
 
44 / 35 (2) +++
Регистрация: 19.09.2013
Можно, конечно, предусмотрительно сгенерировать своего рода радужную таблицу сервисов для всех адресов, их около 4.22 млрд.
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Отладка на сервере Bega DAX: Программирование 6 21.02.2011 15:38
одновременный запуск 2 runBuf - ошибка SHiSHok DAX: Программирование 9 30.10.2009 10:06
gatesasbait: Basic calculator using runbuf() in Dynamics AX Blog bot DAX Blogs 5 29.05.2009 00:13
Формат даты на сервере и клиенте bio_unit DAX: Администрирование 2 25.08.2004 16:44
Функция RunBuf Maxim Gorbunov DAX: База знаний и проекты 0 27.11.2001 17:15
Опции темы Поиск в этой теме
Поиск в этой теме:

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

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

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

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 01:05.