29.08.2017, 11:28 | #21 |
Участник
|
не перепутал ли ты RunbaseProgress, RunBase, SysOperationProgress и SysOperation в этом сообщении?
|
|
29.08.2017, 11:49 | #22 |
Участник
|
Цитата:
Что позволяет предположить. а не перепутал ли ты с чем-то? Ок. Расскажи свое видение картины. Только чтобы в нем обязательно был SysOperationSandbox. Просто потому что тема ветки SysOperationSandbox. |
|
29.08.2017, 11:55 | #23 |
Участник
|
Ну вот тебе один из вариантов - надо было сделать похоже на облако. в облаке есть Azure Functions - который как раз и представляет собой статический метод с параметрами.
сделали так-же https://docs.microsoft.com/en-us/azu...azure-function |
|
|
За это сообщение автора поблагодарили: mazzy (10). |
29.08.2017, 12:18 | #24 |
Участник
|
хочешь сказать, что ЭТО не было придумано для аксапты.
а ЭТО является калькой с чего-то другого? .....оооооо....хм.... Цитата:
Сначала он не понял меня. Потом задумался глубоко. Впервые в жизни я тогда увидел, как изо рта у Агасфера Лукича идёт зеленоватый дым, — зрелище по первому разу жутковатое.
|
|
29.08.2017, 13:01 | #25 |
Участник
|
Цитата:
Судя по тому, что ты сказал "* класс обработка (в стандарте) не занимается своим состоянием, инициализацией и восстановлением параметров, не имеет доступа к UI. В частности, не может отображать прогресс и не может информировать пользователя о своем состоянии." Для тебя ускользнула разница между SysOperationProgress и RunBaseProgress - то есть ты прочитал использованные термины неаккуратно и додумал их значение. Цитата:
/// <summary> /// The <c>SysOperationSandbox</c> class is an internal class for running synchronous operations /// on client side async sessions /// </summary> См., например, SysOperationServiceController X++: public final void runOperation() { if (executionMode == SysOperationExecutionMode::Synchronous) { SysOperationSandbox::startOperation(this); } else { // route through the base class to call run or // enqueue in batch super(); } } Давай я пофикшу твое утверждение как я его понимаю: Итак, старый добрый RunBase (SysOperationProgress): * одна операция один класс * в одном классе замешаны хранилище данных, маршаллинг данных, диалог, собственно обработка * допускается наследование классов-обработок * предоставляется фреймворк, от которого надо унаследовать свой класс и встроиться в фреймворк * отлаживать надо один класс * класс полностью управляет своим состоянием, инициализацией и восстановлением параметров, отображенем себя в UI. В частности, сам занимается отображением своего прогресса и прочим информированием пользователя о своем состоянии. Новый SysOperation (уже обсужался неоднократно): * несколько формально и синтаксически независимых, но при этом очень сильно семантически связанных классов сервис зависит от контракта, контракт может засисеть от UI билдера, билдер засисит от контракта, контроллер зависит от сервиса - это все декларировано * наследовать от базовых классов не нужно (нет базовых классов) (кроме сервиса и UI builder) * встраивание во фреймворк происходит через атрибуты (и соответственно, через рефлекшн) (кроме сервиса и UI builder) * создание классов-наследников от собственного происходит с трудом (потому что атрибуты не наследуются) Атрибуты наследуются и перекрываются. * [класс обработка (в стандарте) не занимается своим состоянием, инициализацией и восстановлением параметров, не имеет доступа к UI. В частности, не может отображать прогресс и не может информировать пользователя о своем состоянии. Может отображать прогресс (см примеры использования SysOperationProgress). У обработки нет состояния а есть только параметры (контракт), параметры могут перекрыть SysPackable и управлять своей серилизации по сути изменений два: 1. (атрибуты наследуются) вместо наследования - не наследуемые атрибуты 2. вместо все-в-одном - группа очень тесно связанных классов 3. (сервис это обычный класс со статическими методами) вместо обычного класса - обязательно сервис К сожалению, в Ax7 не доделали стандартную обработку прогресса и единственный UI что для RunBase, что для SysOP FW - это бегущие точки. Почему не доделали, вопрос сложный, надо понять над чем client team работала вместо этого и рыться в багтрекере. |
|
|
За это сообщение автора поблагодарили: Logger (3), mazzy (2). |
29.08.2017, 13:24 | #26 |
Участник
|
Цитата:
Мне кажется с точки зрения языка программирования типа X++ естественно представить операцию как метод с параметрами, а не как класс, у которого часть полей это параметры а часть внутреннее состояние процесса выполнения. То есть Разнести(Накладную, Сегодня) или Накладная.Разнести(Сегодня) а не - создать разноску накладной - разноскаНакладной.накладная = накладная - разноскаНакладной.дата = сегодня - разноскаНкаладной.Запустить() |
|
29.08.2017, 13:45 | #27 |
Участник
|
Макс, спасибо.
Цитата:
Цитата:
И SysOperationSandbox отсутствовал раньше, ТО значит ли это, что раньше синхронные запросов на клиентской стороне нельзя было выполнить? ЕСЛИ синхронные запросов на клиентской стороне без SysOperationSandbox можно было выполнить ТО почему это SysOperationSandbox часть фреймворка, а не надстройка над ним? Цитата:
и судя по статье, ссылку на которую я привел в самом начале, класс предназначен для работы с ним напрямую. собственно в этом и вопрос - почему за информирование пользователя в данном классе отвечает ВЫЗЫВАЮЩАЯ сторона, а не сам класс, как было в старые добрые времена. Да, Спасибо. Не буду придираться к деталям. Спрошу про одно - ты просто перевернул мое восприятие: Цитата:
Давай уточню вопрос. Пусть есть два класса. Bar - потомок Foo. Foo помечен атрибутом. X++: class MyClassAttibute extends Attribute { } class MyMethodAttibute extends Attribute { } [MyClassAttribute] Class Foo { [MyMethodAttribute] void myMethod(); } Class Bar extends Foo { void myMethod(); } Значит ли это что в Аксапте метод класса Bar тоже помечен атрибутом? |
|
29.08.2017, 14:24 | #28 |
Участник
|
Цитата:
В принципе, как анализировать атрибуты оставлено на усмотрение фреймворка и я не вижу в SysOP специальных усилий чтобы их наследовать. Наверное мне пока не попадалась задача перекрыть параметр но при этом не меняя метку. |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
29.08.2017, 14:42 | #29 |
Участник
|
А могу я все-таки еще один вопрос по твоему тексту?
Цитата:
но почему ты говоришь "выполнять синхронные запросы на клиентской стороне"? ведь сейчас любой, абсолютно любой код X++ выполняется на сервере. что ты имеешь в виду? |
|
29.08.2017, 15:02 | #30 |
Участник
|
Цитата:
Сообщение от mazzy
ЕСЛИ SysOperationSandbox - это часть SysOperation FW для выполнения синхронных запросов на клиентской стороне И SysOperationSandbox отсутствовал раньше, ТО значит ли это, что раньше синхронные запросов на клиентской стороне нельзя было выполнить? ЕСЛИ синхронные запросов на клиентской стороне без SysOperationSandbox можно было выполнить ТО почему это SysOperationSandbox часть фреймворка, а не надстройка над ним? эта часть была не оформлена. В Ax7 ее выделили в статический метод (extract method) и стали использовать снаружи недокументировав. То есть эта штука используется самим sysop fw И предоставляет возможность снаружи вызывает один частный случай (не оборачивая старый способ вызова а наоборот, выделив его). |
|
29.08.2017, 15:53 | #31 |
Участник
|
Цитата:
Есть еще одна гипотеза, что в связи с тем, что сейчас аксапта считает что если операция выполнялась дольше какого-то времени, она зависла и паникует, то пришлось делать некий Sandbox чтобы делать синхронно с точки зрения вызова, но асинхронно с точки зрения движка. В-общем, надо посмотреть что там внутри. |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
29.08.2017, 16:15 | #32 |
Участник
|
вооот.
и возвращаемся к началу темы |
|
29.08.2017, 16:49 | #33 |
Участник
|
Глянул в код.
Sandbox это новый механизм, который позволяет выполнять длительные операции в отдельной сессии но при этом асинхронно, показывая стандартную форму ожидания асинхронной операции (то есть с точки зрения фреймфорка UI тред продолжает принимать сообщения, с точки зрения пользователя см SysOperationSandboxForm). Он используется: - В RunBaseBatch (надо перекрыть метод canRunInNewSession и вызывать runOperation вместо run) - В SysOperation (см выше при синхронном вызове) - Напрямую (это то, что приведено в блоге) То есть если нужны навороты, пользуйтесь старыми фреймворками. Если есть просто статический метод который может долго выполняться, то дергайте напрямую, чтоб не блокировать обработку событий UI. Я не вижу тут ничего извращенного. Жалко только прогрессбар для операций не реализовали |
|
29.08.2017, 16:57 | #34 |
Участник
|
canRunInNewSession можно использовать только для обработок, которые не используют файлы. с этой штукой class File не работает.
|
|
30.08.2017, 02:41 | #35 |
NavAx
|
Цитата:
Т.е. если нужен инструментарий удобный для внедренца, его надо писать отдельно. Но т.к. удобство внедренца в приоритетах не значится, систему неожиданно изменят и инструмент придется преписывать заново. По этой причине хороших инструментов на рынке мало. И по этой причине на внедрежи в бюджет не укладываются и бывают проблемы с прохождением аудита. И поэтому продукт агонизирует. И поэтому на замену AX выстраивается линейка 365 компонент.
__________________
Isn't it nice when things just work? Последний раз редактировалось macklakov; 30.08.2017 в 02:54. |
|
30.08.2017, 09:00 | #36 |
Участник
|
|
|
30.08.2017, 09:40 | #37 |
Участник
|
X++: File::SendStringAsFileToUser(xmlDoc.xml(), fileName); |
|
30.08.2017, 17:12 | #38 |
Участник
|
По памяти,
SysOperationSandbox для того, чтобы запустить любой статический метод из UI (юзер нажал кнопку и тп) и при этом показать некий фидбек юзеру. Решает проблемы - 1. Показать прогресс бар нереально, ибо что там внутри статического метода неизвестно 2. Браузер убьет сессию если сессия не отвечает долгое время 3. Юзер нажмет туже кнопку опять и опять и опять и вообще будет в непонятках что происходит Аналог в 2012 - зависший клиент. Или запуск батча на клиенте без отправки на сервер. Тоесть SysOperationSandbox надо использовать тогда, когда на кнопку повесили функционал, который может выполнятся продолжительное время, но при этом в большинстве случаев займет пару секунд. Или юзер должен дождатся результата выполнения. Как чел описал в блоге, проблему можно решить по разному (например, element.runAsync() или реализовать батч). Цитата:
теперь информировать должен вызывающий класс, а процесс-обработчик должен молчать в тряпочку...
Цитата:
почему именно такая архитектура?
__________________
AxAssist 2012 - Productivity Tool for Dynamics AX 2012/2009/4.0/3.0 |
|
|
За это сообщение автора поблагодарили: mazzy (2), Vadik (1), belugin (3). |
31.08.2017, 09:47 | #39 |
Участник
|
Вообще говоря, процесс мог бы использовать некое API, чтобы информировать окружающих о своем состоянии, а обрабатывать эту информацию показом прогрессбара, обновление какой-нибудь записи в БД или просто ничего не деланьем могла бы UI-запускалка.
|
|
20.01.2021, 14:49 | #40 |
Участник
|
Цитата:
Как мне кажется она не потеряла своей актуальности. У меня как раз возникла проблема, после длительной операции, более 10 мин, нужно вернуть пользователю файл с данными. Чтобы сессия не отвалилась в обычный RunBaseBatch класс был добавлен метод canRunInNewSession = true. и действительно в методе Run класс File отказывается работать. Нигде не нашел подсказок как обойти это, только благодаря этой ветке это стало возможным. Делюсь опытом возможно кому то пригодиться: в Run методе после того как закончилось заполнение объекта файла, *StreemIO в моем примере или любого другого файла, содержимое файла необходимо перегнать в строковую переменную которая участвует в Pack/Unpack. Затем, после выполнения RunOperation вызвать код отправки файла пользователю. X++: class Test_RunbaseBatch extends RunBaseBatch { // Packed variables str csvFileContent; #define.CurrentVersion(1) #localmacro.CurrentList csvFileContent #endmacro public container pack() { return [#CurrentVersion,#CurrentList]; } public void run() { if (! this.validate()) throw error(""); commaStreamIo iO = commaStreamIo::constructForWrite(); container header = ["Num"]; iO.writeExp(header); int i; for (i=1; i<=660; i++) { iO.write(i); // sleep(1000); //Over 10 min. sleep(100); } System.IO.Stream stream = iO.getStream(); stream.Position = 0; System.IO.StreamReader reader = new System.IO.StreamReader(stream); csvFileContent = reader.ReadToEnd(); } public void runAfterOperation() { Filename filename = "file.csv"; File::SendStringAsFileToUser(csvFileContent, filename, System.Text.Encoding::Unicode); info(strFmt("CSV file %1 Sent to user",filename)); } public boolean runsImpersonated() { return true; } public boolean unpack(container packedClass) { Version version = RunBase::getVersion(packedClass); ; switch (version) { case #CurrentVersion: [version,#CurrentList] = packedClass; break; default: return false; } return true; } public boolean validate(Object _calledFrom = null) { if (false) return checkFailed(""); return true; } static ClassDescription description() { return "Test RunBase"; } static Test_RunbaseBatch construct() { return new Test_RunbaseBatch(); } static void main(Args args) { Test_RunbaseBatch runBase; runBase = Test_RunbaseBatch::construct(); if (runBase.prompt()) { runBase.runOperation(); runBase.runAfterOperation(); } } protected boolean canRunInNewSession() { return true; } } Последний раз редактировалось kair84; 20.01.2021 в 15:04. |
|
|
За это сообщение автора поблагодарили: Vadik (1), trud (2). |