客户端未收到ODP.NET通知

时间:2016-10-19 14:28:56

标签: oracle notifications odp.net

我有以下部署:

A)服务器机器:

  • Windows 7 - 64位 - SP1(英文)
  • Oracle Database 11g Express Edition
  • ODAC 11.2.0.1.2(仅安装了Oracle Instant Client 11.2.0.1.0)

B)客户机:

  • Windows 7 - 32位 - SP1(西班牙语)
  • Microsoft .NET Framework 4.0
  • ODAC 11.2.0.1.2(完全安装)

在客户端计算机中,我有一个非常简单的应用程序,它执行以下步骤:

  1. 创建OracleConnection
  2. 创建OracleCommand(SELECT FIELD FROM TABLE)
  3. 根据上一个命令
  4. 创建OracleDependency

    执行这些步骤后,我可以在DBA_CHANGE_NOTIFICATION_REGS表中看到已插入新记录。此记录中的信息与我的客户端设置(用户连接,IP地址,IP端口)完全匹配。

    然后,我修改了数据库,确保在此修改后要通知的查询结果发生了变化。应该通知我的申请,但事实并非如此。

    我已经检查过(使用Wireshark),在修改之后,一些流量通过DBA_CHANGE_NOTIFICATION_REGS中指定的端口从服务器发送到客户端,但是客户端应用程序没有得到通知。

    因此,似乎正确创建了通知,还发送了从服务器到客户端计算机的通知,但通知未到达应用程序。

    客户端还需要什么才能收到通知?

    提前致谢....

    这里是我正在使用的代码:

    private void buttonConnectOracle_Click(object sender, EventArgs e)
    {
        String constr = "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.164.10.202)(PORT=30005))" + 
                        "(CONNECT_DATA=(SID=MASI)));User Id=dbuser;Password=dbuserpasswd;";
    
        try
        {
            OracleCon = new OracleConnection(constr);
            OracleCon.Open();
            buttonConectarOracle.Enabled = false;
            RegisterOracleCommandDependency();
        }
        catch (Exception E)
        {
            MessageBox.Show(String.Format("ERROR connecting with Oracle BD: {0}{0}Connection string: {1}{0}{0}Error:{0}{2}", "\n\r", constr, E.Message));
        }
    }
    
    private void RegisterOracleCommandDependency()
    {
        String sql = "SELECT * FROM SCEHMA.REF";
        OracleCommand command = new OracleCommand(sql, OracleCon);
    
        OracleDep = new OracleDependency(command);
        command.Notification.IsNotifiedOnce = false;
    
        command.ExecuteNonQuery();
    
        OracleDep.OnChange += new Oracle.DataAccess.Client.OnChangeEventHandler(OnMyNotificationOracle);
    }
    
    public void OnMyNotificationOracle(object src, OracleNotificationEventArgs args) 
    {
        String logStr = "Notification received at " + DateTime.Now.ToString();
        //TODO: Add logStr to log
    }
    

4 个答案:

答案 0 :(得分:1)

首先,感谢@b_levitt,@ yopez83和@Christian Shay的贡献。

问题已经解决:某些Oracle Server版本与相应的Oracle客户端版本之间存在不兼容问题。

总结一下,当Server为11.2.0.2.0且Client为11.2.0.1.2时,通知不起作用。

此查询提供有关Oracle服务器版本的信息:

select * from v$version;

就我而言,输出如下:

Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
CORE 11.2.0.2.0 Production
TNS for 64-bit Windows: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production

希望这有帮助......

答案 1 :(得分:1)

只是添加到上面列出的不兼容版本; 我在Oracle 11g 11.2.0.3.0版(64位)和使用ODP.NET(Oracle.ManagedDataAccess)版本12.1.24160719时遇到了同样的问题。

在USER_CHANGE_NOTIFICATION_REGS表中获取一个条目(主机IP与我的客户端IP不匹配,但是,嗯...)此条目在大约30秒后被删除。 OnChangeEventHandler在插入时从未在.Net客户端中触发(使用基于对象的通知)。

两者都做了:

GRANT CHANGE NOTIFICATION TO [USER]
GRANT EXECUTE ON DBMS_CHANGE_NOTIFICATION TO [USER]

尝试从nuget现在提供的其他ODP.NET客户端版本,低至10.1.21。没有用。执行插入时,Wireshark在端口1005(由OracleDependency使用)上检测不到任何流量。叹息。

更新:事实证明,由于在服务器上设置了IP重定向,回调失败了,所以在这种情况下不要责怪Oracle ......提示始终要验证IP地址在USER_CHANGE_NOTIFICATION_REGS中指定。

答案 2 :(得分:0)

检查documentation。我认为它可以帮助您完成通知。

另请参阅this,如果之前的链接没有帮助。

答案 3 :(得分:0)

也许这可以帮助

using (OracleConnection OraConn = new OracleConnection(conString))
{
    using (OracleCommand OraComm = OraConn.CreateCommand())
    {
        try
        {
            OracleDependency OraDep = new OracleDependency(OraComm);
            OraComm.AddRowid = true;
            OraComm.CommandText = crawlORACLEServer;
            OraComm.CommandType = System.Data.CommandType.Text;
            OraComm.Notification.IsNotifiedOnce = false;
            OraDep.OnChange += OraDep_OnChange;

            if (OraConn.State == System.Data.ConnectionState.Closed) OraConn.Open();

            dynamic f = await OraComm.ExecuteNonQueryAsync();

            bRet = true;
        }
        catch (OracleNullValueException eN)
        {
            message = eN.Message;
        }
        catch (OracleTruncateException OT)
        {
            message = OT.Message;
        }
        catch (OracleTypeException eT)
        {
            message = eT.Message;
        }
        catch (OracleException ex)
        {
            message = ex.Message;
        }
        catch (Exception e)
        {
            message = e.Message;
        }
        finally
        {
            OraComm.Dispose();
            OraConn.Dispose();
        }
    }
}