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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 24.02.2012, 06:41   #1  
CHESER85 is offline
CHESER85
Участник
 
93 / 11 (1) +
Регистрация: 04.08.2011
Адрес: Ufa
Записей в блоге: 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;

    }
Обработка ошибки подразумевает лишь то, что на компьютере пользователя не установлен драйвер FireBird. Но вот сегодня я выяснил что иногда сервер, где лежит база, может быть выключен либо недоступен. В этом случае все равно выдается предложение установить драйвер. Вопрос - как выяснить нужный мне код ошибки и внедрить проверку именно на данный код ошибки? Заранее спасибо!
Старый 24.02.2012, 08:41   #2  
ice321i is offline
ice321i
Участник
 
60 / 47 (2) +++
Регистрация: 22.10.2007
Через сокет попробуй подсоединиться к серверу на тот порт где крутится 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);
Смотри форму tutorial_TicTacToe.
Старый 24.02.2012, 09:36   #3  
CHESER85 is offline
CHESER85
Участник
 
93 / 11 (1) +
Регистрация: 04.08.2011
Адрес: Ufa
Записей в блоге: 1
Цитата:
Сообщение от 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);
Смотри форму tutorial_TicTacToe.

к сожалению не нашел эту форму т.к. у меня 4.0! а где указывать ай пи адрес сервера и порт?
Старый 24.02.2012, 12:36   #4  
someOne is offline
someOne
Участник
Аватар для someOne
 
173 / 423 (15) +++++++
Регистрация: 11.12.2008
Адрес: Москва
Почему бы не использовать NET ? (Работа FireBird(FDB) в AX 2009)

Зачем все эти извращения с ODBC и DLL на клиенте ? Это прошлый век ИМХО.

Ведь можно установить клиентскую библиотеку подключения к FB (NET) на сервер АОС и обращается к FB только оттуда!

Проверить работоспособность сервера FB можно перехватывая исключения в методе
(что то типа)
X++:
try
{
  connection.Open();
}
catch(Exception::CLRError)
{
  
}
Старый 24.02.2012, 12:39   #5  
someOne is offline
someOne
Участник
Аватар для someOne
 
173 / 423 (15) +++++++
Регистрация: 11.12.2008
Адрес: Москва
Еще можете воспользоваться такой функцией (тоже 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  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,651 / 1158 (42) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
1. Устанавливать что-либо автоматически - категорически не рекомендуется. У пользователя банально может не быть прав на эту операцию. Кроме того, как правило, подобные установки требуют перезагрузку операционной системы.

2. Как следствие, не надо здесь "мудрить". Произошла ошибка - просто прекращайте обработку. Далее пользователь должен Вам выслать снимок экрана с текстом ошибки или Вы ее записываете где-то себе в лог ошибок и ВРУЧНУЮ разбираетесь как с причиной, так и ищите пути исправления.

Это не тот случай, где нужно что-то автоматизировать. Время и силы, потраченные на подобную автоматизацию никогда не окупяться. Слишком много всего надо будет проверять. Например, может быть еще вылет по timeOut. Может быть не корректно указан логин/пароль. Да мало ли что еще...

Насчет обязательной установки драйвера мы у себя решили эту проблему следующим образом. Драйвер ставится на тот компьютер, где крутится AOS. Установка соединения и запросы выполняются на стороне сервера (RunOn = Server). Как следствие, нет необходимости ставить драйвера на клиентские машины.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
За это сообщение автора поблагодарили: CHESER85 (1).
Старый 24.02.2012, 21:42   #7  
ice321i is offline
ice321i
Участник
 
60 / 47 (2) +++
Регистрация: 22.10.2007
Если 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  
CHESER85 is offline
CHESER85
Участник
 
93 / 11 (1) +
Регистрация: 04.08.2011
Адрес: Ufa
Записей в блоге: 1
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
1. Устанавливать что-либо автоматически - категорически не рекомендуется. У пользователя банально может не быть прав на эту операцию. Кроме того, как правило, подобные установки требуют перезагрузку операционной системы.

2. Как следствие, не надо здесь "мудрить". Произошла ошибка - просто прекращайте обработку. Далее пользователь должен Вам выслать снимок экрана с текстом ошибки или Вы ее записываете где-то себе в лог ошибок и ВРУЧНУЮ разбираетесь как с причиной, так и ищите пути исправления.

Это не тот случай, где нужно что-то автоматизировать. Время и силы, потраченные на подобную автоматизацию никогда не окупяться. Слишком много всего надо будет проверять. Например, может быть еще вылет по timeOut. Может быть не корректно указан логин/пароль. Да мало ли что еще...

Насчет обязательной установки драйвера мы у себя решили эту проблему следующим образом. Драйвер ставится на тот компьютер, где крутится AOS. Установка соединения и запросы выполняются на стороне сервера (RunOn = Server). Как следствие, нет необходимости ставить драйвера на клиентские машины.
Попробовал воспользоваться вашим советом, но, к сожалению, при установке RunOn=Server все равно запросы происходят на клиенте сам не знаю почему
Старый 27.02.2012, 12:03   #9  
ice321i is offline
ice321i
Участник
 
60 / 47 (2) +++
Регистрация: 22.10.2007
Вот рабочий пример проверки соединения по определенному порту сервера, проверял на 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  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,651 / 1158 (42) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от CHESER85 Посмотреть сообщение
Попробовал воспользоваться вашим советом, но, к сожалению, при установке RunOn=Server все равно запросы происходят на клиенте сам не знаю почему
Еще раз напомню, что установка соединения и выполнения запроса происходит в классах CCADO... (CCADOConnection, CCADOCommand, CCADOFields, CCADOField, CCADORecordSet) Другими словами, надо смотреть свойство RunOn у этих классов.

В младших версиях Axapta у них это свойство было "Called From". Т.е. откуда вызвали, там и работают. Но вот в Ax2009 уже стоит Client. Посмотрите, что стоит в Вашей версии.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 28.02.2012, 06:21   #11  
CHESER85 is offline
CHESER85
Участник
 
93 / 11 (1) +
Регистрация: 04.08.2011
Адрес: Ufa
Записей в блоге: 1
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Еще раз напомню, что установка соединения и выполнения запроса происходит в классах CCADO... (CCADOConnection, CCADOCommand, CCADOFields, CCADOField, CCADORecordSet) Другими словами, надо смотреть свойство RunOn у этих классов.

В младших версиях Axapta у них это свойство было "Called From". Т.е. откуда вызвали, там и работают. Но вот в Ax2009 уже стоит Client. Посмотрите, что стоит в Вашей версии.
Поменял у классов CCADO* значение RunOn на Server, и вот что выдало при запуске:
Сбой запроса на разрешение типа "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  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5788 (200) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Ну как бы логично На сервере для работы с "небезопасными" API, включая COM, надо разрешение запрашивать. Запрос пока можно вынести в джобик и через пункт меню запускать его на сервере.
Старый 10.07.2013, 17:59   #13  
konfet is offline
konfet
Снова балуюсь косаптой :)
 
143 / 50 (2) ++++
Регистрация: 23.04.2003
Адрес: Moscow
Цитата:
Сообщение от ice321i Посмотреть сообщение
Вот рабочий пример проверки соединения по определенному порту сервера, проверял на 5, должно работать и для 4:
X++:
static void ConnectToServer(Args _args)
{
    System.Net.Sockets.TcpClient tcpClient;
    ;

    tcpClient = new System.Net.Sockets.TcpClient();
...
}

В том-то и дело, что для 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;
}
Метод, возвращающий (серверный) путь к экзешнику tcping.exe:
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;
}
метод shellExecuteWait() взят отсюда.
__________________
Бесты и регарды!
Старый 15.07.2013, 10:25   #14  
michel1971 is offline
michel1971
Участник
 
76 / 63 (3) ++++
Регистрация: 14.01.2011
вот 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

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Метод "open" в COM-объекте класса "ADODB.Connection" возвратил код ошибки 0x80004005 (E_FAIL) Poleax DAX: Программирование 14 01.10.2013 14:15
Как программно узнать текущий объект и метод в котором выполняется код? McCoy DAX: Программирование 15 25.02.2011 23:34
Dundas.mailer-код ошибки 0x80020009 donMigel DAX: Прочие вопросы 4 06.10.2010 10:28
Метод "SendMail" в COM-объекте класса "Dundas.mailer" возвратил код ошибки 0x80004005 (E_FAIL), который означает: The RCPT command failed. The specified account does not exist. Андрей К. DAX: Программирование 3 10.07.2009 16:08
Метод 'SendMail' в COM-объекте класса 'Dundas.mailer' возвратил код ошибки 0x80004005 (E_FAIL), который означает: The HELLO command failed. Andrew Akhmetov DAX: Программирование 4 09.04.2008 13:24
Опции темы Поиск в этой теме
Поиск в этой теме:

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

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

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

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 11:42.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.