Click here to Skip to main content
15,885,216 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hi All,

I do not have a lot of experience with manually constructed async calls and keeping threads alive. And I suspect my question here is something to do with my lack of understanding in this.

I am looking to implement the Oracle Database Change Notification (same as this person) but in a C#.Net framework 4.0 web API. In my test, I want to get a single integer from a database table, and store it in a web server application cache. Then subscribe to the Oracle Database Change Notification system so when the database value changes, the Web API is called, which in turn updates the cache and resubmits the Oracle Database Change Notification request.

I have used the code in this article which is a console application and it works fine. I also found this example which I can get working using WCF and a subscription mechanism. However, I cannot get this to work in my Web API

I can get the data from the table initially, and like the WCF example, I setup an Oracle Dependency at the same time. I can see that this dependency is created on the USER_CHANGE_NOTIFICATION_REGS table and when I make a change on the database, it appears that the database sends the notification because the record disappears from USER_CHANGE_NOTIFICATION_REGS (which is what happens with the working examples). But my 'OnChange' event does not fire.

As I said, I think this is my lack on knowledge in the world of threads and async programming. I have been looking at async and await specifically, but the example code I have used does not seem to match up with the model (I may be wrong on this). I am doing some more reading around on the subject, but I was wondering if anyone could give me any comments on this. Some example code below.

The web api is really simple. It checks the application cache first
C#
[HttpGet]
public string CanDo()
{
    bool newValue;
    string cachedValue = HttpContext.Current.Application["MyValue"] as string;
    if (cachedValue != null)
    {
        newValue = (cachedValue == "0");
    }
    else
    {
        newValue = (RegisterOracleWatch() == 0);
    }
    return newValue;
}


The manager is very similar to the example code from the oracle site. The OracleDependency _dep is declared at the top of the class.
C#
private int RegisterOracleWatch()
{
    int res = 0; // assume success for this test

    try
    {
        HttpContext.Current.Application.Lock();

        using (var con = new OracleConnection(constr))
        {
            var cmd = new OracleCommand("select val from myTable ", con);
            con.Open();

            _dep = new OracleDependency(cmd);
            _dep.OnChange += OnOracleWatchNotificaton;
            object result = cmd.ExecuteScalar();

            if (null != result)
            {
                res = Convert.ToInt32(result);
                HttpContext.Current.Application["MyValue"] = res.ToString();
            }
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
    finally
    {
        HttpContext.Current.Application.UnLock();
    }
    return res;
}


Finally the return function is also simple. It just re-registers the Oracle Notification. But this function is not getting called.

C#
public void OnOracleWatchNotificaton(object sender, OracleNotificationEventArgs e)
{
    try { RegisterOracleWatch(); }
    catch (Exception ex){ throw ex; }
}


If anyone can give me any pointers on where I should go with this, it would be greatly appreciated.
Thanks

p.s. I have checked that the ports are open
Posted
Updated 17-Apr-15 5:07am
v2

If this works in a WCF and console assembly, exactly as you've written it. Then my guess is that IIS is running your Web API on a per-call instance and your instance is getting teared down at the return of your method call, thereby preventing the callback on your event.

This is normal behavior for the ASP.Net Web API technology. What you are trying to do might not be a good fit. There is a hacky way to enforce session behavior in the technology as I found in a quick google search.
 
Share this answer
 
Hi Jacob, thanks for the response.

It turns out that I had 3 problems;
1. As you suggested, the instance that was making the call to the database was getting reared down. Moving it to a call from Application_Start() helped there.
2. I needed to update my Oracle client. I was
using Oracle.DataAccess.Client
and needed to upgrade to
using Oracle.ManagedDataAccess.Client

3. I then had a problem with port blocking. The code worked once, then wouldn't work for a couple of minutes, then would work again. This was because my TCP port was not getting closed properly and would stay open/reserved for he default 240 seconds.

Hope this detail helps someone.
 
Share this answer
 
v2
Comments
Jacob Himes 29-Apr-15 5:19am    
That's great. Yeah I learned very quickly that the managed Oracle data provider for .net is muuuuccchhh better. We had many problems with the old data provider and our x64 servers.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900