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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 21.06.2013, 09:49   #1  
EVGL is offline
EVGL
Banned
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
4,445 / 3001 (0) ++++++++++
Регистрация: 09.07.2002
Адрес: Parndorf, AT
AX2012 services - async. HTTP
Добрый день, кому-нибудь удавалось запустить WCF-HTTP-адаптер в AX2012 в асинхронном режиме, чтобы сначала принимал запрос, сохранял в очереди, а отвечал отдельно, когда есть ресурсы?

Кто-нибудь делал исходящий HTTP адаптер (на базе XMLHTTPRequest, к примеру)?
Старый 22.06.2013, 06:59   #2  
Alex_KD is offline
Alex_KD
Участник
AxAssist
MCBMSS
Соотечественники
 
522 / 362 (14) ++++++
Регистрация: 06.07.2006
Адрес: Melbourne, Down Under
Мы ajax'емся к WCF (inbound port) и тянем данные на веб страницу.

Делаем через промежуточный WCF, т.к. напрямую были какие то проблемы плюс нам надо ответ в виде JSON, а не XML. Ответ из AX опять же проще обработать в .NET. По производительности получаем дополнительные 40-100мс на запрос, что вполне терпимо.

Дополнительно, когда inbound port добавляешь в Service Reference в Visual Studio проекте получаешь две функции, например MyFunc и MyFuncAsync. Может тебе просто надо 2ю функцию дернуть?
__________________
AxAssist 2012 - Productivity Tool for Dynamics AX 2012/2009/4.0/3.0
За это сообщение автора поблагодарили: EVGL (10), Kabardian (4).
Старый 24.06.2013, 16:08   #3  
EVGL is offline
EVGL
Banned
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
4,445 / 3001 (0) ++++++++++
Регистрация: 09.07.2002
Адрес: Parndorf, AT
Alex_KD - 10 points!

Сказал Visual Studio "Generate async. calls", написал вот такой код - работает!
Код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace VendGroupUpdate
{
    class Program
{        
        static void Main(string[] args)
        {
            VendGroupService.CallContext                context = new VendGroupService.CallContext();
            VendGroupService.EntityKey[]                keys;
            VendGroupService.KeyField                   keyField;
            VendGroupService.AxdVendGroup               vendGroup;
            DateTime        timeNow;
            IAsyncResult    result;
            int i;
            AsyncCallback cb = new AsyncCallback(Program.VendGroupCallback);            
            ;

            context.Company = "USMF";

            for (i = 1; i <= 1000; i++) // Try 1000 parallel calls
            {

                VendGroupService.VendGroupServiceClient client = new VendGroupService.VendGroupServiceClient();
                client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Anonymous;

                keys = new VendGroupService.EntityKey[1];
                keys[0] = new VendGroupService.EntityKey();
                keyField = new VendGroupService.KeyField();
                keyField.Field = "VendGroup";
                keyField.Value = "10";
                keys[0].KeyData = new VendGroupService.KeyField[1] { keyField };

                vendGroup = new VendGroupService.AxdVendGroup();
                vendGroup.VendGroup = new VendGroupService.AxdEntity_VendGroup[1];
                vendGroup.VendGroup[0] = new VendGroupService.AxdEntity_VendGroup();
                vendGroup.VendGroup[0].VendGroup = "10";
                vendGroup.VendGroup[0].Name = i + " " + System.DateTime.Now.ToShortTimeString();
                vendGroup.VendGroup[0]._DocumentHash = "XYZ";
                vendGroup.VendGroup[0].action = VendGroupService.AxdEnum_AxdEntityAction.replace;

                try
                {
                    timeNow = System.DateTime.Now;

                    Console.WriteLine("Start call " + i);

                    //client.update(context, keys, vendGroup);

                    result = client.Beginupdate(context, keys, vendGroup, null/*cb*/, client);

                    Console.WriteLine("Call ended. Acknowledge: " + result.AsyncState.ToString());
                    Console.WriteLine("Delay: " + (-timeNow.Subtract(System.DateTime.Now)).ToString());
                }
                catch (Exception e)
                {
                    Console.WriteLine("Exception: " + e.Message);
                    client.Abort();
                }
                //client.Close();            
            }                    
            Console.ReadKey();
        }


        public static void VendGroupCallback(IAsyncResult ar)
        {
            VendGroupService.VendGroupServiceClient client = (VendGroupService.VendGroupServiceClient) ar.AsyncState;

            client.Endupdate(ar);

            Console.WriteLine("Callback fired.");
        }
    }
}
На самом деле это - симуляция, конечно. На сервер отправляется Request, .NET держит сессию и делает где-то в своих глубинах цикл, потом вызывает функцию Callback по указателю, передавая ей Response.

Последний раз редактировалось EVGL; 24.06.2013 в 17:52.
Старый 26.06.2013, 02:25   #4  
hardcore is offline
hardcore
Участник
 
16 / 32 (2) +++
Регистрация: 02.11.2006
Добрый день EVGL , пардон за много букв, надеюсь мои размышления окажутся хоть сколько-нибудь полезными.

Я правильно понимаю, что у вас проблема с обработкой реквестов на стороне аксапты, т.е кол-во реквестов в единицу времени не слишком большое но каждый реквест выполняется очень долго? И судя по вопросу вы готовы вкладываться в разработку которая позволит клиенту отложено понимать что запрос на сервере выполнен.
Если да то можете рассмотреть следующий варианты (я привел все пару самых незамысловатых хотя на практике их гораздо больше) раз аксапта разработчики начинают активно использовать дот.нет.
Если нет то поясните в чем у вас техническая трудность?
Как говорил Alex_KD тут нужно использовать промежуточный WCF, так как сервисы акспаты несколько урезаны с точки зрения технической функциональности.
  1. Взаимодействия в 2 стороны если клиентом является другая система например сайт и такое взаимодействие вообще разрешено административной политикой (наверно это как-то отвечает на ваш пункт с XMLHTTPRequest):
    а) Развернуть wcf сервис над ах, развернуть wcf сервис на клиенте. Клиент вызывает сервис над ах, асинхронно (имеется ввиду стандартный для .net подход
    ) запускает операцию в ах и возвращает управление, когда операция завершается, она вызывает сервис клиента передавая результат. На клиенте лежит логика по корреляции запроса с ответом.
    б) Также более красивый вариант, но не всегда реализуемый из-за ограничений со стороны админов. Реализовать сервис с CallbackContract так называемые дуплексные службы. С технической точки зрения это также вызов в 2 стороны, только коррелировать на клиенте ничего не надо, вы сделаете вызов клиентом вам вернется управления сразу, а когда сервер закончит выполнять запрос на клиенте сработает обработчик.

  2. Если схема предусматривает только вызов со стороны клиента на сервер, а так обычно бывает если системы находятся «далеко друг от друга» и в компании сильна административная политика или взаимодействие между системами в разных компаниях:
    а) Способ в лоб: То вы можете также вызвать клиентом сервис над ах из него запустить операцию в ах асинхронно, по завершении выполнения просто сохранять результат в сериализованнов виде например в базе. А клиент должен периодически опрашивать сервер. Минусы подхода со стороны клиента, что придется писать логику повторного забора результата.

    б) Этот вариант вряд ли сходу может быть рабочий, указал только для полноты картины:
    В настройках своего wcf сервиса вы можете задать параметры InstanceContextMode= PerSession
    По умолчанию этот параметр равен perCall, то есть каждый раз когда вы делаете вызов операции на сервисе у вас создается новый экземпляр класса сервиса, если же вы поставите параметр persession то при вызове с одного клиента экземпляр класса будет один, это позволит вам также как и в первом случае вызвать код в ах и вернуть управление, а клиент должен периодически опрашивать сервис. Минусы этого подхода со стороны клиента очевидны, со стороны сервера можно напортачить с доступом к одним и тем же данным в разных потоках, т.к. wcf вам гарантирует только что для одного клиента будет работать экземпляр одного и того же сервиса но вот что вызов операций в этом экземпляре будет проходить из одно и того же потока не гарантируется.
    с) Есть еще совсем новый вариант работы через websockets но для этого нужно использовать windows server 2012 или windows 8 (сейчас только на них iis поддерживает эту технологию). Логика как и в пункте 1б + PerSession из пункта 2б, да и код похожий, и с точки зрения http взаимодействия администраторам глаза не мазолит т.к. вызовы все технически происходят со стороны клиента, такая надстройка над http вообщем.
p.s.
Вообще http устроен как протокол без состояний это дает наибольшую производительность, т.е. сервер не хранит состояние в памяти между вызовами клиента, а практически любая вещь (не считая кода 100 Continue) связанная с сессией (о том что сервер как бы помнит что это за клиент, храня его состояние в памяти постоянно) уже строится поверх http и снижает производительность.
Что касается «асинхронных http» запросов, которые вы можете делать через .net это конечно асинхронно только со стороны клиента. Клиент, делая вызов асинхронно может не ждать ответа от сервера, а продолжать исполнять код текущего потока, а ответ, который сервер обработал синхронно, приходит в другой поток клиента, после чего он становиться доступен в пользовательском обработчике. В общих чертах это можно найти здесь
За это сообщение автора поблагодарили: EVGL (10), Logger (1).
Старый 26.06.2013, 11:36   #5  
EVGL is offline
EVGL
Banned
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
4,445 / 3001 (0) ++++++++++
Регистрация: 09.07.2002
Адрес: Parndorf, AT
Благодарю за глубокий ответ.

Цитата:
Сообщение от hardcore Посмотреть сообщение
Я правильно понимаю, что у вас проблема с обработкой реквестов на стороне аксапты, т.е кол-во реквестов в единицу времени не слишком большое но каждый реквест выполняется очень долго? И судя по вопросу вы готовы вкладываться в разработку которая позволит клиенту отложено понимать что запрос на сервере выполнен.
Совершенно верно. Опыт на моем компьютере показал, что доставка сообщения через все уровни абстракции занимает 30 мс, тогда как полная обработка простейшего запроса требует 2 с. Клиент требует ответ <1с.

Цитата:
Сообщение от hardcore Посмотреть сообщение
Развернуть wcf сервис над ах, развернуть wcf сервис на клиенте. Клиент вызывает сервис над ах, асинхронно (имеется ввиду стандартный для .net подход
Этого хотелось бы избежать, поскольку надстройка неминуемо скроет WSDL-описание, а клиент предъявляет высокие требования к администрированию и контролю версий схем и моделей данных. В противном случае можно сразу брать MSMQ-адаптор и не мучиться.


Цитата:
Сообщение от hardcore Посмотреть сообщение
Способ в лоб: То вы можете также вызвать клиентом сервис над ах из него запустить операцию в ах асинхронно, по завершении выполнения просто сохранять результат в сериализованнов виде например в базе. А клиент должен периодически опрашивать сервер. Минусы подхода со стороны клиента, что придется писать логику повторного забора результата.
Этот способ я пробовал с той разницей, что вызывался стандартный сервис в AX. Минус в том, что WCF-клиент все равно проходит по всем методам, и приходится сериализовывать уже де-сериализованный XML-объект, теряя производительность. Кроме того, придется менять сигнатуры и возвращаемые значения всех update-, create- и прочих методов.

Цитата:
Сообщение от hardcore Посмотреть сообщение
Клиент, делая вызов асинхронно может не ждать ответа от сервера, а продолжать исполнять код текущего потока, а ответ, который сервер обработал синхронно, приходит в другой поток клиента, после чего он становиться доступен в пользовательском обработчике. В общих чертах это можно найти здесь
Да, я догадался, что т.н. асинхронный вызов в .NET работает именно так, и это - не более чем программное ухищрение.
Старый 26.06.2013, 14:21   #6  
Vadik is offline
Vadik
Модератор
Аватар для Vadik
Лучший по профессии 2017
Лучший по профессии 2015
 
3,631 / 1849 (69) ++++++++
Регистрация: 18.11.2002
Адрес: гражданин Москвы
А на Azure Service Bus adapter не смотрели еще? Там вроде и Service reference при разработке клиента, и реальная асинхронность. Я не агитирую, просто интересно (возможно сами скоро будем тестировать)
__________________
-ТСЯ или -ТЬСЯ ?
За это сообщение автора поблагодарили: EVGL (5).
Старый 26.06.2013, 14:43   #7  
EVGL is offline
EVGL
Banned
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
4,445 / 3001 (0) ++++++++++
Регистрация: 09.07.2002
Адрес: Parndorf, AT
Цитата:
Сообщение от Vadik Посмотреть сообщение
А на Azure Service Bus adapter не смотрели еще? Там вроде и Service reference при разработке клиента, и реальная асинхронность. Я не агитирую, просто интересно (возможно сами скоро будем тестировать)
Асинхронности, похоже, нет: http://blogs.msdn.com/b/aif/archive/...s-adapter.aspx
Старый 26.06.2013, 16:01   #8  
Alex_KD is offline
Alex_KD
Участник
AxAssist
MCBMSS
Соотечественники
 
522 / 362 (14) ++++++
Регистрация: 06.07.2006
Адрес: Melbourne, Down Under
Цитата:
Сообщение от hardcore Посмотреть сообщение
Минусы этого подхода со стороны клиента очевидны, со стороны сервера можно напортачить с доступом к одним и тем же данным в разных потоках
Чтобы не напортачить есть _DocumentHash в документ сервисах, который можно взять в read и дальше использовать в update.


Цитата:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
Может есть какой метод с помощью которого можно прописать этот (или любой) аттрибут для AX сервиса?

Цитата:
Этого хотелось бы избежать, поскольку надстройка неминуемо скроет WSDL-описание
Новый WCF опубликует свой WSDL-описание, если указать это в web.config.

Цитата:
Совершенно верно. Опыт на моем компьютере показал, что доставка сообщения через все уровни абстракции занимает 30 мс, тогда как полная обработка простейшего запроса требует 2 с. Клиент требует ответ <1с.
Документ сервисы не знаю насколько шустрые, т.к. пока не тестировал. Простейший сервис (не документ) отвечает практически мгновенно (~100мс). С документ сервисом я бы смотрел в стороны уменьшения передаваемых данных. Наверняка тащите кучу ненужных/не используемых/пустых полей туда-сюда.

Евгений, а в вашем примере с 1000 паралельными запросами все ли запросы действительно выполнились паралельно? Все ли запросы выполнились в примерно одинаковый промежуток времени? Что-то мне подсказывает, что первые 200 прошли на ура, а дальше пошел беспредел...
__________________
AxAssist 2012 - Productivity Tool for Dynamics AX 2012/2009/4.0/3.0
Старый 30.06.2013, 00:57   #9  
hardcore is offline
hardcore
Участник
 
16 / 32 (2) +++
Регистрация: 02.11.2006
Цитата:
Сообщение от EVGL:
Этого хотелось бы избежать, поскольку надстройка неминуемо скроет WSDL-описание, а клиент предъявляет высокие требования к администрированию и контролю версий схем и моделей данных. В противном случае можно сразу брать MSMQ-адаптор и не мучиться.
Очередь кстати хороший промышленный вариант для такого типа задач, если такая проблема с производительностью сервисов встречается все время в вашем приложении Ах.

Цитата:
Сообщение от Alex_KD:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
Может есть какой метод с помощью которого можно прописать этот (или любой) аттрибут для AX сервиса?
Я боюсь для Ах сервиса он не поможет, насколько я помню код IL который генерится из Ах сервиса оборачивается в реальный WCF сервис который по-моему уже содержит этот атрибут (то есть настраивается сессия в разрезе логина под которым сервис вызывается и скорее всего она может быть одна и та же для разных Ах сервисов), не помню точно надо смотреть код net.reflectorом или подобной тулзой.
Моя же мысль была что можно воспользоваться преимуществами дот.нет которые дают простой в использовании патерн асинхронного программирования + сессионность wcf, а именно отпускать клиента раньше чем завершилась обработка вызова, а клиент справляясь о результатах всегда попадет на тот же инстанс сервиса который все об обработки этого запроса знает. На х++ пришлось бы запускать отдельный поток на каждый вызов сервиса, и вручную делать синхронизацию между потоками, и т.д. (много нюансов), либо написать небольшую инфраструктуру, вроде очереди куда класть задания, возвращать ответ и пакетником их обрабатывать, в любом случае кода кажется больше придется написать.
Старый 19.07.2013, 09:55   #10  
EVGL is offline
EVGL
Banned
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
4,445 / 3001 (0) ++++++++++
Регистрация: 09.07.2002
Адрес: Parndorf, AT
В продолжение разговора: прилагаю рабочий outbound HTTP Adapter с тестовым сервером впридачу:

SharedProject_AIF_HTTP_Response.xpo
TestHTTPListener_CS.xpo
За это сообщение автора поблагодарили: Logger (5), gl00mie (5), Kabardian (4).
Старый 12.10.2015, 18:41   #11  
Vadik is offline
Vadik
Модератор
Аватар для Vadik
Лучший по профессии 2017
Лучший по профессии 2015
 
3,631 / 1849 (69) ++++++++
Регистрация: 18.11.2002
Адрес: гражданин Москвы
Цитата:
Сообщение от Alex_KD Посмотреть сообщение
С документ сервисом я бы смотрел в стороны уменьшения передаваемых данных. Наверняка тащите кучу ненужных/не используемых/пустых полей туда-сюда
Случайно забрел сюда повторно. Понимаю что Евгению не сильно актуально, но вдруг кому-то пригодится.. Для "тяжелых" в плане количества участвующих таблиц и полей документов (типа клиента, поставщика, продукта) использование data policies с отключением ненужных (неиспользуемых) полей снижает время отклика как раз где-то раза в два-три
__________________
-ТСЯ или -ТЬСЯ ?
За это сообщение автора поблагодарили: Link (1), gl00mie (2), kpoxa (1).
Теги
aif, ax2012, azure service bus, document service, service, законченный пример, производительность

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
emeadaxsupport: Announcing a Major Update to RapidStart Services Online Help Blog bot DAX Blogs 0 21.03.2013 20:11
emeadaxsupport: AX2012 AIF services error - The maximum number of joins allowed (99) is exceeded in the statement. Blog bot DAX Blogs 1 03.07.2012 08:13
DynamicsAxSCM: Product-item data management services Blog bot DAX Blogs 0 06.07.2011 17:11
daxdilip: How to: Configure Dynamics AX AIF Services to listen for SSL Requests (https) Blog bot DAX Blogs 0 23.01.2011 10:12
gatesasbait: Installing Reporting Services, Analysis Services and Enterprise Portal for AX 2009 Blog bot DAX Blogs 0 03.07.2008 02:05

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

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

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