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?
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;
}
}