29.05.2019, 12:57 | #1 |
Участник
|
ax3,ax4,ax2009,ax2012: RunBaseBatch: как правильно добавить действия, которые должны быть выполнены на клиенте? например, импорт из Excel.
Предположим у нас есть RunBaseBatch.
Он делает что-то тяжелое. Мы конечно же хотим сделать так, чтобы он мог работать на пакетном сервере. Но этот класс забирает данные из какого-нибудь файла, который находится на клиенте. Как и куда правильно вставить действия, которые должны выполняться на клиенте? Сейчас правильный способ видится таким: * разбить процесс на два runBaseBatch класса: первый будет иметь свойство RunOn=Client, второй - RunOn=Server * первый в методе run должен будет выполнить клиентские действия, создать второй класс на сервере и передать ему параметры и данные Но что-то как-то слишком сложно. Очень напоминает overprogramming. Может существует другой способ? |
|
29.05.2019, 13:25 | #2 |
Участник
|
На каком именно клиенте?
|
|
29.05.2019, 13:55 | #3 |
Мрачный тип
|
IMHO, проще размещать файл на пакетнике или выделенном сетевом ресурсе с доступом для AOS и не дергать удачу за вымя, пытаясь обойти "радости" объемного клиент-серверного общения
__________________
Мы летаем, кружимся, нагоняем ужасы ... |
|
|
За это сообщение автора поблагодарили: ax_mct (3). |
29.05.2019, 14:24 | #4 |
Участник
|
Шутку оценил. Смешно. Цитата:
Костылем поскольку: * не совсем правильно давать пользователям доступ в общий сетевой ресурс. * не совсем правильно давать доступ АОСу к пользовательским сетевым папкам * не совсем правильно заставлять пользователей перекладывать файлы с места на место (21 век на дворе жеж) И это не попытка обойти объемное клиент-серверное общение. Это попытка понять как правильно разделить обязанности между клиентом и сервером. |
|
29.05.2019, 14:30 | #5 |
Moderator
|
Может быть можно использовать кастомизированную форму вместо диалога, и в этой форме сделать кнопочку для чтения файла, а потом этот файл, как контейнер, передавать назад в RunBaseBatch ? (Я этого никогда не пробовал, но в целом - может и взлететь).
|
|
29.05.2019, 15:02 | #6 |
Участник
|
Все зависит от того, насколько важна безопасность и легкость настройки по сравнению с местом для хранения временем переписывания.
1. run on server и где-то в диалоге переписать файл на сервер а в качестве параметров пакетного задания уже записывать путь на сервере (следует учесть, что в 2012 вызовы с сервера на клиент запрещены и надо будет как-то это обходить) 2. Дать доступ клиенту и серверу к одной папке и хранить путь там 3. Как 1 но в SysOperation framework: UIBuilder переписывает и кладет серверный путь в контракт. Я не помню, где исполняется UI builder в 2012 но, думаю, на клиенте. см также копирование файловмежду уровнями Последний раз редактировалось belugin; 29.05.2019 в 15:05. |
|
30.05.2019, 00:16 | #7 |
Участник
|
Цитата:
Сообщение от mazzy
Предположим у нас есть RunBaseBatch.
Он делает что-то тяжелое. Мы конечно же хотим сделать так, чтобы он мог работать на пакетном сервере. Но этот класс забирает данные из какого-нибудь файла, который находится на клиенте. Как и куда правильно вставить действия, которые должны выполняться на клиенте?
Разумеется, в AX2012 появляются свои заморочки с вызовом клиентского кода, инициированным с сервера, но вроде все решается при желании. А предложенный подход с кастомизированной формочкой - это вроде как раз то, что приходится делать в D365O для импортов из Excel: брать клиентский файл, передавать его во временный каталог на АОСе и там уже с ним работать. |
|
30.05.2019, 08:34 | #8 |
Злыдни
|
Есть одна, возможно дурацкая, идея:
- в диалоге пользователь указывает полный путь к файлу; - если класс необходимо выполнить в пакетном режиме, в момент создания пакетного задания прикрепить к заданию файл; - в обработке читать прикрепленный файл; - в конце задания удалять прикрепленный файл из хранилища (с диска, из БД и т.п.)
__________________
люди...считают, что если техника не ломается, то ее не нужно ремонтировать. Инженеры считают, что если она не ломается, то нуждается в совершенствовании. |
|
|
За это сообщение автора поблагодарили: ax_mct (3). |
30.05.2019, 10:44 | #9 |
Участник
|
Цитата:
Сообщение от mazzy
Предположим у нас есть RunBaseBatch.
Он делает что-то тяжелое. Мы конечно же хотим сделать так, чтобы он мог работать на пакетном сервере. Но этот класс забирает данные из какого-нибудь файла, который находится на клиенте. Как и куда правильно вставить действия, которые должны выполняться на клиенте? Сейчас правильный способ видится таким: * разбить процесс на два runBaseBatch класса: первый будет иметь свойство RunOn=Client, второй - RunOn=Server * первый в методе run должен будет выполнить клиентские действия, создать второй класс на сервере и передать ему параметры и данные Но что-то как-то слишком сложно. Очень напоминает overprogramming. Может существует другой способ? Тогда то, что выполняется на клиенте - это запускает сам клиент (вместо RunBaseBatch - использовать RunBase), но результатом запуска становится не обработанные данные, а сформированное пакетное задание. Вот после обработки этого пакетного задания и получим результат Т.е. логика такая 1. Клиент запускает пункт меню с классом RunBase. Это НЕ пакетное задание 2. Класс загружает нужные данные с клиента. Возможно, записывает в какие-нибудь parm-таблицы 3. Формирует пакетное задание на основе другого класса RunBaseBatch, который и выполняет собственно обработку 4. Для пользователя - работа пункта меню завершена. Но собственно обработка пока не выполнена. Это надо ждать завершение нового пакетного задания Здесь единственный недостаток, что если по окончании обработки необходимо выполнить некие действия на клиенте, то не получится Можно вообще разделить на 2 независимых пункта меню 1. Загрузка данных 2. Обработка ранее загруженных данных Тут можно много всякого разного напридумывать при такой идеологии. И повторная обработка, и просмотр ошибок, и "разбор полетов" на предмет, что загрузили не то. Да мало ли... Но это если в этом есть необходимость, конечно...
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: mazzy (2), ax_mct (5). |
30.05.2019, 11:00 | #10 |
Участник
|
Почему я считаю разделение на 2 класса - нормальным
По той причине, что и собственно загрузка данных, и последующая обработка, очевидно, не тривиальные процессы (раз вообще возник вопрос о необходимости разделения). Т.е. наверняка много кода (много методов) будет как для загрузки, так и для обработки. И если это все пихать в один RunBase, то получим безумное количество методов в одном классе с которыми потом будет очень тяжело разбираться (есть печальный опыт ) Поэтому просто формальное разделение методов по разным классам - уже хорошо. Даже если это будет банальный вызов одного из другого без каких-либо пакетных заданий 1. RunBase - диалог с пользователем и "диспетчер" для вызова других классов 2. Класс - загрузчик данных 3. Класс - обработчик данных Ну, а получив в явном виде разделение процессов по разным классам позже можно будет подумать о запуске этих процессов по отдельности. В разных пакетных заданиях, например...
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
30.05.2019, 17:26 | #11 |
Участник
|
msmq не подойдет?
|
|
30.05.2019, 20:10 | #12 |
Banned
|
Цитата:
Сообщение от mazzy
Предположим у нас есть RunBaseBatch.
Он делает что-то тяжелое. Мы конечно же хотим сделать так, чтобы он мог работать на пакетном сервере. Но этот класс забирает данные из какого-нибудь файла, который находится на клиенте. Как и куда правильно вставить действия, которые должны выполняться на клиенте? Сейчас правильный способ видится таким: * разбить процесс на два runBaseBatch класса: первый будет иметь свойство RunOn=Client, второй - RunOn=Server * первый в методе run должен будет выполнить клиентские действия, создать второй класс на сервере и передать ему параметры и данные Но что-то как-то слишком сложно. Очень напоминает overprogramming. Может существует другой способ? Клиентом пишем в базу. Можно при желании уменьшить обращения но это уже оптимизация редко нужная. Временная DB таблица или staging если нужна история. Сервер берет из базы. В пакетнике или нет, не так важно. Смысла жонглировать классами - не вижу. Практически всегда вдруг возникает требование видеть историю или статус валидации, а это staging. А там где staging все приходит к ParmId и Line Status и может еще пара параметров типа даты и пр. |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
30.05.2019, 20:16 | #13 |
Участник
|
Прям руками? В отдельную таблицу?
Почему не saveLast? если saveLast, то в какое место класса RunBase вставить вызов? если использовать стандартный вызов saveLast, то в какое место вставить импорт из Excel? |
|
31.05.2019, 02:47 | #14 |
Banned
|
Цитата:
Выделял бы RunId на каждый запуск и именно его бы и передавал помимо фильтров. Операция загрузки данных на сервер в staging конечно руками и не так важно где этот код. С точки зрения дизайна решения предварительная загрузка данных с клиента на сервер мне кажется наиболее прямым решением. Можно и просто копировать файл на сервер, а не писать в базу. Но предварительная операция как загрузка на сервер как принцип. То есть разбиваем на операции, а не классы. Если что-то реальное сложное то я бы даже предлагал бы wizard с шагами до кнопки OK пакетника. И солидно, и голова меньше болит когда логика по шагам. |
|
31.05.2019, 03:04 | #15 |
Banned
|
Потому что страшно. Что он там и как сохраняет с какими таймаутами и размерами не подконтрольно. Может там TempDB потом взорвется или еще что. Не предназначено saveLast для данных в принципе.
Руками в свою таблицу и передача RecId как ссылки на загруженные в DB данные - оно более как то и спокойнее и проще. |
|
31.05.2019, 08:35 | #16 |
Участник
|
Хорошо, возвращаемся к исходному вопросу:
RunBaseBatch: как правильно добавить действия, которые должны быть выполнены на клиенте? например, Последний раз редактировалось mazzy; 31.05.2019 в 08:45. |
|
31.05.2019, 10:23 | #17 |
Участник
|
getFromDialog вместо того, чтобы сохранять имя файла как есть (или вместе с этим если надо, например, в следующий раз показать тот же путь) выгружает на сервер и запоминает RecID в поле, recID входит в список упаковки и дальше обрабатывается так же как и все другие поля. Отличия только в UI
|
|
31.05.2019, 10:26 | #18 |
Участник
|
Цитата:
Еще, насколько я помню, при передаче больших файлов на сервер надо порциями передавать большой контейнер, чтобы он уместился в буфер RPC. |
|
31.05.2019, 10:56 | #19 |
Участник
|
getFromDialog в стандарте вызывается из метода closeOk/checkCloseOk
другими словами, getFromDialog вызывается ДО закрытия диалога если в getFromDialog добавить долгую обработку, то диалог будет висеть перед пользователем очень долгое время и не реагировать ни на какие нажатия, что приводит пользователя в ступор. если getFromDialog добавить долгую обработку И SysOperationProgress/RunBaseProgress, то Аксапта уводит окно с диалогом в background и пользователь как правило больше диалог достать не может а если во время длинной операции внутри getFromDialog произойдет ошибка, то пользователь увидит инфолог, но диалог не закроется и не будет виден пользователю. можно я повторю вопрос: RunBaseBatch: как правильно добавить действия, которые должны быть выполнены на клиенте? например, импорт из Excel. Цитата:
Сообщение от belugin
Если кто-то запустит не в пакетном режиме, то для того, чтобы использовать saveLast надо как-то разделять SysLastValue по разным фактам запуска.
Еще, насколько я помню, при передаче больших файлов на сервер надо порциями передавать большой контейнер, чтобы он уместился в буфер RPC. Теперь мой вопрос понятен? RunBaseBatch: как правильно добавить действия, которые должны быть выполнены на клиенте? например, импорт из Excel. |
|
31.05.2019, 15:33 | #20 |
Banned
|
Цитата:
Одного единственного номера достаточно как HeaderRecId запуска для всех файлов. Это конечно от UI если предполагается ручной выбор файла и одноразовый пакетник. Если это папка то на клиенте ей делать нечего так как Batch это сервер. Извиняюсь если сбиваю с темы расчленения RunBaseBatch. |
|
Теги |
как правильно |
|
|