24.02.2012, 06:41 | #1 |
Участник
|
как узнать код ошибки при подключении к базе?
Подключаюсь к базе FireBird используя приблизительно такой код:
X++: try { // cn.connection().open("..."); cn.connection().open("DRIVER={Firebird/InterBase(r) driver};..."); command.activeConnection(cn); } catch (Exception::Error) { if (box::yesNo('Для работы данного отчета требуется драйвер ODBC FireBird. Установить его?',DialogButton::Yes) == DialogButton::Yes) { WinApi::copyFile(...,false); if (WinApi::shellExecute(...) { retry; } else return false; } else return false; } |
|
24.02.2012, 08:41 | #2 |
Участник
|
Через сокет попробуй подсоединиться к серверу на тот порт где крутится firebird. Если соединение прошло успешно значит сервер и служба доступны
Примерно так: X++: #Socks int socket; DLL dll; DLLFunction func; ; dll = new DLL('WS2_32.dll'); func = new DLLFunction(dll,'socket'); func.arg(ExtTypes::DWord,ExtTypes::DWord,ExtTypes::DWord); func.returns(ExtTypes::DWord); socket = func.call(#AF_INET,#SOCK_STREAM,#IPPROTO_IP); |
|
24.02.2012, 09:36 | #3 |
Участник
|
Цитата:
Сообщение от ice321i
Через сокет попробуй подсоединиться к серверу на тот порт где крутится firebird. Если соединение прошло успешно значит сервер и служба доступны
Примерно так: X++: #Socks int socket; DLL dll; DLLFunction func; ; dll = new DLL('WS2_32.dll'); func = new DLLFunction(dll,'socket'); func.arg(ExtTypes::DWord,ExtTypes::DWord,ExtTypes::DWord); func.returns(ExtTypes::DWord); socket = func.call(#AF_INET,#SOCK_STREAM,#IPPROTO_IP); к сожалению не нашел эту форму т.к. у меня 4.0! а где указывать ай пи адрес сервера и порт? |
|
24.02.2012, 12:36 | #4 |
Участник
|
Почему бы не использовать NET ? (Работа FireBird(FDB) в AX 2009)
Зачем все эти извращения с ODBC и DLL на клиенте ? Это прошлый век ИМХО. Ведь можно установить клиентскую библиотеку подключения к FB (NET) на сервер АОС и обращается к FB только оттуда! Проверить работоспособность сервера FB можно перехватывая исключения в методе (что то типа) X++: try { connection.Open(); } catch(Exception::CLRError) { } |
|
24.02.2012, 12:39 | #5 |
Участник
|
Еще можете воспользоваться такой функцией (тоже NET)
Она может "пинговать" сервер по адресу, и выдаст информацию о его доступности по сети X++: static server boolean ping(str _serverAddress) { System.Net.NetworkInformation.Ping pingSender; System.Net.NetworkInformation.PingReply reply; ; new InteropPermission(InteropKind::ClrInterop).assert(); pingSender = new System.Net.NetworkInformation.Ping(); reply = pingSender.Send(_serverAddress, 1000); if (reply.get_Status() == System.Net.NetworkInformation.IPStatus::Success) { return true; } return false; } |
|
|
За это сообщение автора поблагодарили: coolibin (2). |
24.02.2012, 15:14 | #6 |
Участник
|
1. Устанавливать что-либо автоматически - категорически не рекомендуется. У пользователя банально может не быть прав на эту операцию. Кроме того, как правило, подобные установки требуют перезагрузку операционной системы.
2. Как следствие, не надо здесь "мудрить". Произошла ошибка - просто прекращайте обработку. Далее пользователь должен Вам выслать снимок экрана с текстом ошибки или Вы ее записываете где-то себе в лог ошибок и ВРУЧНУЮ разбираетесь как с причиной, так и ищите пути исправления. Это не тот случай, где нужно что-то автоматизировать. Время и силы, потраченные на подобную автоматизацию никогда не окупяться. Слишком много всего надо будет проверять. Например, может быть еще вылет по timeOut. Может быть не корректно указан логин/пароль. Да мало ли что еще... Насчет обязательной установки драйвера мы у себя решили эту проблему следующим образом. Драйвер ставится на тот компьютер, где крутится AOS. Установка соединения и запросы выполняются на стороне сервера (RunOn = Server). Как следствие, нет необходимости ставить драйвера на клиентские машины.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: CHESER85 (1). |
24.02.2012, 21:42 | #7 |
Участник
|
Если 4 то можно и через .NET.
X++: #define.Port( ); #define.Server('сервер на котором запущена служба'); System.Net.Sockets.TcpClient tcpClient; ; tcpClient = new System.Net.Sockets.TcpClient(); tcpClient.Connect(#Server, #Port); if(!tcpClient.Connected) throw error("Сервер не доступен"); Последний раз редактировалось ice321i; 24.02.2012 в 21:56. |
|
27.02.2012, 06:53 | #8 |
Участник
|
Цитата:
Сообщение от Владимир Максимов
1. Устанавливать что-либо автоматически - категорически не рекомендуется. У пользователя банально может не быть прав на эту операцию. Кроме того, как правило, подобные установки требуют перезагрузку операционной системы.
2. Как следствие, не надо здесь "мудрить". Произошла ошибка - просто прекращайте обработку. Далее пользователь должен Вам выслать снимок экрана с текстом ошибки или Вы ее записываете где-то себе в лог ошибок и ВРУЧНУЮ разбираетесь как с причиной, так и ищите пути исправления. Это не тот случай, где нужно что-то автоматизировать. Время и силы, потраченные на подобную автоматизацию никогда не окупяться. Слишком много всего надо будет проверять. Например, может быть еще вылет по timeOut. Может быть не корректно указан логин/пароль. Да мало ли что еще... Насчет обязательной установки драйвера мы у себя решили эту проблему следующим образом. Драйвер ставится на тот компьютер, где крутится AOS. Установка соединения и запросы выполняются на стороне сервера (RunOn = Server). Как следствие, нет необходимости ставить драйвера на клиентские машины. |
|
27.02.2012, 12:03 | #9 |
Участник
|
Вот рабочий пример проверки соединения по определенному порту сервера, проверял на 5, должно работать и для 4:
X++: static void ConnectToServer(Args _args) { System.Net.Sockets.TcpClient tcpClient; ; tcpClient = new System.Net.Sockets.TcpClient(); try { tcpClient.Connect('www.yandex.ru', 80); if(tcpClient.get_Connected()) { info("Сервер доступен"); tcpClient.Close(); } } catch(Exception::CLRError) { error("Ошибка при подключении к серверу"); } } |
|
|
За это сообщение автора поблагодарили: CHESER85 (1). |
27.02.2012, 20:21 | #10 |
Участник
|
Цитата:
В младших версиях Axapta у них это свойство было "Called From". Т.е. откуда вызвали, там и работают. Но вот в Ax2009 уже стоит Client. Посмотрите, что стоит в Вашей версии.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
28.02.2012, 06:21 | #11 |
Участник
|
Цитата:
Сообщение от Владимир Максимов
Еще раз напомню, что установка соединения и выполнения запроса происходит в классах CCADO... (CCADOConnection, CCADOCommand, CCADOFields, CCADOField, CCADORecordSet) Другими словами, надо смотреть свойство RunOn у этих классов.
В младших версиях Axapta у них это свойство было "Called From". Т.е. откуда вызвали, там и работают. Но вот в Ax2009 уже стоит Client. Посмотрите, что стоит в Вашей версии. Сбой запроса на разрешение типа "InteropPermission". (S)\Classes\InteropPermission\demand (S)\Classes\COM\new (S)\Classes\CCADOConnection\new - line 4 (C)\Jobs\GidInOutReport - line 20 Error Сообщение (08:18:21) Объект "COM" не может быть создан |
|
28.02.2012, 06:59 | #12 |
Участник
|
Ну как бы логично На сервере для работы с "небезопасными" API, включая COM, надо разрешение запрашивать. Запрос пока можно вынести в джобик и через пункт меню запускать его на сервере.
|
|
10.07.2013, 17:59 | #13 |
Снова балуюсь косаптой :)
|
Цитата:
В том-то и дело, что для 4-ки работает хреново Иногда вылетает с эксепшеном, иногда без эксепшена - просто не доходит до конца кода. И еще, помимо вылетов, важный недостаток - нельзя настроить таймаут, который определяет, сколько надо ждать ответа от удаленного сервера, перед тем как посчитать его недоступным. Я нашел в сети простую утилитку, которая работает для серверов как внутри сети (за фаерволлом), так и вне ее. Работает примитивно, но зато надежно. Использую прежде всего для определения доступности удаленного (связанного) SQL-сервера, по порту 1433. Таймаут определен в три секунды, можно поставить и меньше. Утилитку надо положить в каталог Include приложения. X++: #define.PingSuccess('1 successful, 0 failed') #define.PingFailed('0 successful, 1 failed') #WInAPI static server boolean ping3(ServerName _ServerName, str 10 _port = '80') { boolean res, xSuccess, xFailed; // одна секунда ожидания str templateStr = '-4 -n 1 -w 1 %1 %2 > %3'; str paramStr, outputStr, commandStr; fileName xTCPingEXE; fileName xFileName, xDir; TextBuffer TextBuffer = new TextBuffer(); Counter i; ; xDir = WinAPIServer::getTCPing(true); xTCPingEXE = WinAPIServer::getTCPing(false); xFileName = xDir + curUserId() + '_ping.txt'; paramStr = strFmt(templateStr, _ServerName, _port, xFileName); commandStr = 'CMD /c ' + xTCPingEXE + ' ' + paramStr; // три секунды ожидания WinAPI_R::shellExecuteWait(commandStr, 3000); TextBuffer.fromFile(xFileName); outputStr = TextBuffer.getText(); xSuccess = strscan(outputStr, #PingSuccess, 1, strlen(outputStr)) ? true : false; xFailed = strscan(outputStr, #PingFailed, 1, strlen(outputStr)) ? true : false; if (xSuccess == xFailed) { throw error("Непонятный результат пинга!"); } WinAPIServer::deleteFile(xFileName); return xSuccess; } X++: static server fileName getTCPing(boolean _directoryOnly = false) { filename xdir, xfile; ; xdir = xInfo::directory(DirectoryType::Include) + @'TCPing\'; xfile = xInfo::directory(DirectoryType::Include) + @'TCPing\tcping.exe'; if (!WinAPIServer::fileExists(xfile)) { throw info(strFmt(' %1', xfile)); } return _directoryOnly ? xdir : xfile; }
__________________
Бесты и регарды! |
|
15.07.2013, 10:25 | #14 |
Участник
|
вот ping через стандартную виндовую DLL (ICMP.DLL)
X++: client static container ping(str _ipStr, int _timeOut = 5000) { // IP_STATUS codes returned from IP APIs #WinApi #define.IP_STATUS_BASE(11000) #define.IP_SUCCESS(0) #define.IP_BUF_TOO_SMALL(#IP_STATUS_BASE + 1) #define.IP_DEST_NET_UNREACHABLE(#IP_STATUS_BASE + 2) #define.IP_DEST_HOST_UNREACHABLE(#IP_STATUS_BASE + 3) #define.IP_DEST_PROT_UNREACHABLE(#IP_STATUS_BASE + 4) #define.IP_DEST_PORT_UNREACHABLE(#IP_STATUS_BASE + 5) #define.IP_NO_RESOURCES(#IP_STATUS_BASE + 6) #define.IP_BAD_OPTION(#IP_STATUS_BASE + 7) #define.IP_HW_ERROR(#IP_STATUS_BASE + 8) #define.IP_PACKET_TOO_BIG(#IP_STATUS_BASE + 9) #define.IP_REQ_TIMED_OUT(#IP_STATUS_BASE + 10) #define.IP_BAD_REQ(#IP_STATUS_BASE + 11) #define.IP_BAD_ROUTE(#IP_STATUS_BASE + 12) #define.IP_TTL_EXPIRED_TRANSIT(#IP_STATUS_BASE + 13) #define.IP_TTL_EXPIRED_REASSEM(#IP_STATUS_BASE + 14) #define.IP_PARAM_PROBLEM(#IP_STATUS_BASE + 15) #define.IP_SOURCE_QUENCH(#IP_STATUS_BASE + 16) #define.IP_OPTION_TOO_BIG(#IP_STATUS_BASE + 17) #define.IP_BAD_DESTINATION(#IP_STATUS_BASE + 18) // The next group are status codes passed up on status indications to // transport layer protocols. #define.IP_ADDR_DELETED(#IP_STATUS_BASE + 19) #define.IP_SPEC_MTU_CHANGE(#IP_STATUS_BASE + 20) #define.IP_MTU_CHANGE(#IP_STATUS_BASE + 21) #define.IP_UNLOAD(#IP_STATUS_BASE + 22) #define.IP_GENERAL_FAILURE(#IP_STATUS_BASE + 50) #define.MAX_IP_STATUS(#IP_GENERAL_FAILURE) #define.IP_PENDING(#IP_STATUS_BASE + 255) #define.INADDR_NONE(0xFFFFFFFF) int ipAddress; int ICMPPort; Binary PingReply; Binary ReplyOption; DLL _winApiDLL; DLLFunction IcmpCreateFile; DLLFunction IcmpCloseHandle; DLLFunction IcmpSendEcho; str 50 PingStatusToStr (int StatusCode) { str ret; switch (StatusCode) { case #IP_SUCCESS: ret = 'IP_SUCCESS'; break; case #IP_BUF_TOO_SMALL: ret = 'IP_BUF_TOO_SMALL'; break; case #IP_DEST_NET_UNREACHABLE: ret = 'IP_DEST_NET_UNREACHABLE'; break; case #IP_DEST_HOST_UNREACHABLE: ret = 'IP_DEST_HOST_UNREACHABLE'; break; case #IP_DEST_PROT_UNREACHABLE: ret = 'IP_DEST_PROT_UNREACHABLE'; break; case #IP_DEST_PORT_UNREACHABLE: ret = 'IP_DEST_PORT_UNREACHABLE'; break; case #IP_NO_RESOURCES: ret = 'IP_NO_RESOURCES'; break; case #IP_BAD_OPTION: ret = 'IP_BAD_OPTION'; break; case #IP_HW_ERROR: ret = 'IP_HW_ERROR'; break; case #IP_PACKET_TOO_BIG: ret = 'IP_PACKET_TOO_BIG'; break; case #IP_REQ_TIMED_OUT: ret = 'IP_REQ_TIMED_OUT'; break; case #IP_BAD_REQ: ret = 'IP_BAD_REQ'; break; case #IP_BAD_ROUTE: ret = 'IP_BAD_ROUTE'; break; case #IP_TTL_EXPIRED_TRANSIT: ret = 'IP_TTL_EXPIRED_TRANSIT'; break; case #IP_TTL_EXPIRED_REASSEM: ret = 'IP_TTL_EXPIRED_REASSEM'; break; case #IP_PARAM_PROBLEM: ret = 'IP_PARAM_PROBLEM'; break; case #IP_SOURCE_QUENCH: ret = 'IP_SOURCE_QUENCH'; break; case #IP_OPTION_TOO_BIG: ret = 'IP_OPTION_TOO_BIG'; break; case #IP_BAD_DESTINATION: ret = 'IP_BAD_DESTINATION'; break; case #IP_ADDR_DELETED: ret = 'IP_ADDR_DELETED'; break; case #IP_SPEC_MTU_CHANGE: ret = 'IP_SPEC_MTU_CHANGE'; break; case #IP_MTU_CHANGE: ret = 'IP_MTU_CHANGE'; break; case #IP_UNLOAD: ret = 'IP_UNLOAD'; break; case #IP_GENERAL_FAILURE: ret = 'IP_GENERAL_FAILURE'; break; default: ret = ''; break; } return ret; } PingReply = new Binary(256); ReplyOption = new Binary(256); _winApiDLL = new DLL(#ICMP); IcmpCreateFile = new DLLFunction(_winApiDLL, 'IcmpCreateFile'); IcmpCloseHandle = new DLLFunction(_winApiDLL, 'IcmpCloseHandle'); IcmpSendEcho = new DLLFunction(_winApiDLL, 'IcmpSendEcho'); IcmpCreateFile.returns(ExtTypes::DWord); IcmpCloseHandle.arg(ExtTypes::DWord); IcmpCloseHandle.returns(ExtTypes::DWord); IcmpSendEcho.arg(ExtTypes::DWord, ExtTypes::DWord, ExtTypes::String, ExtTypes::DWord, ExtTypes::DWord, ExtTypes::Pointer, ExtTypes::DWord, ExtTypes::DWord); IcmpSendEcho.returns(ExtTypes::DWord); ipAddress = WinApi::isIPAddress(_ipStr); if (ipAddress == #INADDR_NONE) throw error(strfmt("Передаваемый параметр %1 не является IP адресом", _ipStr)); ICMPPort = IcmpCreateFile.call(); if(ICMPPort == #INVALID_HANDLE_VALUE) throw error(strfmt("Вызов функции %1 завершился с ошибкой", "IcmpCreateFile")); IcmpSendEcho.call(ICMPPort, ipAddress, "", 0 , 0, PingReply, 256 ,_timeOut); IcmpCloseHandle.call(ICMPPort); return [PingReply.dWord(#offset4), PingStatusToStr(PingReply.dWord(#offset4))]; } |
|
Теги |
firebird, ping |
|
|