Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SqlDependency with EntityFramework 6 (async)

I'm using the EF 6 async querying features, such as

var list = await cx.Clients.Where(c => c.FirstName.Length > 0).ToListAsync();

I want to also start SQL dependencies on these queries so that I can get notified when the data in the database changes. I can do this using the System.Runtime.Remoting.Messaging.CallContext as follows:

    async Task GetData()
    {
        using (ClientsContext context = new ClientsContext()) // subclass of DbContext
        {

            SqlDependency.Start(context.Database.Connection.ConnectionString);
            SqlDependency dependency = new SqlDependency();
            dependency.OnChange += (sender, e) =>
                {
                    Console.Write(e.ToString()); 
                };

            System.Runtime.Remoting.Messaging.CallContext.SetData("MS.SqlDependencyCookie", dependency.Id);
            var list = await context.Clients.Where(c => c.FirstName.Length > 0).ToListAsync();
        }
    }

.. and it works fine. But I am running into an issue if I want to have an SqlDependency on more than one query. If I have two async methods similar to GetData() above, and I run both at the same time, only the first one will get change notifications. I assume that this is due to the CallContext having the cookie set by each method in succession. If I wait for the first async method to complete, then call the second, they both get change notifications as expected. Is there any solution to this?

like image 776
user1032657 Avatar asked Jun 27 '13 05:06

user1032657


1 Answers

I'm not too familiar with SqlDependency, but the below will allow your CallContext to have the correct value at the time ToListAsync is called (When multiple calls are running). Proof of concept here, https://dotnetfiddle.net/F8FnFe

    async Task<List<Client>> GetData()
    {
        using (ClientsContext context = new ClientsContext()) // subclass of DbContext
        {
            SqlDependency.Start(context.Database.Connection.ConnectionString);
            SqlDependency dependency = new SqlDependency();
            dependency.OnChange += (sender, e) =>
            {
                Console.Write(e.ToString());
            };

            Task<List<Client>> task = Task<Task<List<Client>>>.Factory.StartNew(async () =>
            {
                System.Runtime.Remoting.Messaging.CallContext.SetData("MS.SqlDependencyCookie", dependency.Id);
                var list = await context.Clients.Where(c => c.FirstName.Length > 0).ToListAsync();
            }).Unwrap();

            return await task;
        }
    }
like image 197
Kenneth Ito Avatar answered Oct 22 '22 10:10

Kenneth Ito