I have below code for SqlDependency. Below call back function is get called every time when data reader is executed. Rather than this call back function not get executing when i change some value in Table.
public IEnumerable<Messages> GetAllMessages()
{
var messages = new List<Messages>();
using (var connection = new SqlConnection(_connString))
{
connection.Open();
using (var command = new SqlCommand("SELECT SUM(MessageID) FROM [dbo].[Messages] group by Message", connection))
{
command.Notification = null;
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
// messages.Add(item: new Messages { MessageID = (int)reader["MessageID"], Message = (string)reader["Message"], EmptyMessage = reader["EmptyMessage"] != DBNull.Value ? (string)reader["EmptyMessage"] : "", MessageDate = Convert.ToDateTime(reader["Date"]) });
}
}
}
return messages;
}
CallBack:
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
MessagesHub.SendMessages();
}
}
Any Help please!
Related
I have a Signalr Hub to notify user when have a new data inserted to Database
hub
public class NotifyHub : Hub
{
public void NotifyAllClients(string source, string msg)
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<NotifyHub>();
context.Clients.All.displayNotification(source, msg);
}
}
Client
$(function () {
var notify = $.connection.notifyHub;
notify.client.displayNotification = function (source,msg) {
new PNotify({
title: source,
text: msg,
type: 'success',
styling: 'bootstrap3'
});
};
$.connection.hub.logging = true;
$.connection.hub.start();
});
client default.aspx codebehind
protected void Page_Load(object sender, EventArgs e)
{
SendNotifications();
}
public void SendNotifications()
{
string message = string.Empty;
string source = string.Empty;
string conStr = ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString;
using (SqlConnection connection = new SqlConnection(conStr)) {
string query = "SELECT [Source], [MSG] FROM [dbo].[LOG_EVENT] ORDER BY LOG_DATE DESC, LOG_TIME DESC";
using (SqlCommand command = new SqlCommand(query, connection)) {
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += dependency_OnChange;
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows) {
reader.Read();
source = reader(0).ToString();
message = reader(1).ToString();
}
}
}
NotifyHub nHub = new NotifyHub();
nHub.NotifyAllClients(source, message);
}
but this notify to all client when user connected to hub It caused multiple notify pop up to all user that use webpage.
I know that I can use caller property to notify to just caller, but this property not working with IHubContext I can't find any solution to solve this
Hi I have some method which send me data from sql table and I want that - when I click button in datagridview - that send parameter to the method and parameter will have ID value(like on picture 107 or 106). Below on the picture is datagridview with 2 buttons and ID column.
public ObservableCollection<MyClass> ReadUpdate(int id_update)
{
ObservableCollection<MyClass> result = new ObservableCollection<MyClass>();
string nwConn = System.Configuration.ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
SqlDataReader dr;
SqlConnection conn = new SqlConnection(nwConn);
try
{
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = conn;
cmd.CommandText = "Insert_Update";
cmd.Parameters.AddWithValue("#id_update", id_update);
conn.Open();
dr = cmd.ExecuteReader();
while (dr.Read())
{
MyClass lin = new MyClass();
lin.id = dr.GetInt32(1);
if (!dr.IsDBNull(2)) lin.other = dr.GetString(2);
if (!dr.IsDBNull(3)) lin.barkod = dr.GetString(3);
if (!dr.IsDBNull(4)) lin.pw = dr.GetInt32(4);
result.Add(lin);
}
dr.Close();
return result;
}
catch (SqlException e)
{
MyClass lin = new MyClass();
lin.other = e.Message;
result.Add(lin);
return result;
}
finally
{
conn.Close();
};
}
My class:
public class PIS
{
public int ID { get; set; }
}
And my button:
private void btnUpdate_Click(object sender, System.Windows.RoutedEventArgs e)
{
pis_update = (PIS)((Button)sender).DataContext;
ChildWindow_Update childWindow_update = new ChildWindow_Update();
childWindow_update.DataContext = ((Pismo)((Button)sender).DataContext).Id_Pismo;
childWindow_update.Closed += ChildWindow_Update_Closed;
childWindow_update.Show();
}
public ChildWindow_Update()
{
InitializeComponent();
ServiceReference1.Service1Client webService = new ServiceReference1.Service1Client();
webService.ReadUpdateAsync((int)this.DataContext);
webService.ReadUpdateCompleted += WebService_ReadUpdateCompleted;
private void WebService_ReadUpdateCompleted(object sender, ServiceReference1.ReadUpdateCompletedEventArgs e)
{
if (e.Result != null)
{
//do something
}
}
I have error in webService.ReadUpdateAsync((int)this.DataContext);
"Null REference Exception".
At the time of your constructor call, your DataContext has not been set yet. You should make the id a constructor parameter if you need it in the constructor.
Generally speaking, you should use MVVM and the command pattern, where you can specify your id data as the command parameter in your XAML.
I have written this class to automate SQLDependencys
public class DatabaseChangeAlert
{
private String connectionString;
private SqlConnection sc;
public event EventHandler<DatabaseChangedEvent> DatabaseChangeEvent;
private String tabelle;
private String query;
public DatabaseChangeAlert(String tabelle, String conString)
{
try
{
this.tabelle = tabelle;
this.sc = new SqlConnection(conString); ;//new SqlConnection(GlobalResources.ConnectionString);
this.connectionString = conString;
String sel = "";
using (SqlConnection con = new SqlConnection(conString))
{
con.Open();
SqlCommand cmd = con.CreateCommand();
cmd.CommandText = "SELECT dbo.syscolumns.name AS Spaltenname " +
" FROM dbo.syscolumns INNER JOIN " +
" dbo.sysobjects ON dbo.syscolumns.id = dbo.sysobjects.id " +
" WHERE (dbo.sysobjects.xtype = 'U') and dbo.sysobjects.name='" + tabelle + "' ";
using (SqlDataReader sr = cmd.ExecuteReader())
{
while (sr.Read())
{
sel += "["+sr.GetString(0)+"],";
}
}
sel = sel.Substring(0, sel.Length - 1);
}
query = "SELECT " + sel + " from [dbo].[" + tabelle+"]";
}
catch (Exception ex) { }
}
~DatabaseChangeAlert()
{
if(connectionString!=null)
SqlDependency.Stop(connectionString);
}
public void start()
{
try
{
SqlDependency.Start(connectionString);
}
catch (Exception ex)
{
// log(ex)
}
try
{
startDependency();
}
catch (Exception ex)
{
// log(ex)
}
}
private void startDependency()
{
// Assume connection is an open SqlConnection.
// Create a new SqlCommand object.
using (SqlCommand command = new SqlCommand(query, sc))
{
sc.Open();
// Create a dependency and associate it with the SqlCommand.
SqlDependency dependency = new SqlDependency(command);
// Maintain the refence in a class member.
// Subscribe to the SqlDependency event.
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
// Execute the command.
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
}
}
sc.Close();
}
}
void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Info != SqlNotificationInfo.Invalid)
{
startDependency();
if (DatabaseChangeEvent != null)
{
DatabaseChangeEvent(this, new DatabaseChangedEvent(tabelle,e.Info));
}
}
}
public class DatabaseChangedEvent : EventArgs
{
public readonly String Tablename;
public readonly SqlNotificationInfo info;
public DatabaseChangedEvent(String tablename,SqlNotificationInfo info)
{
this.Tablename = tablename;
this.info = info;
}
}
}
in my program I use this Class like that:
DatabaseChangeAlert alerttz = new DatabaseChangeAlert("table1", GlobalResources.ConnectionString);
alerttz.DatabaseChangeEvent += (e,d)=>{
MessageBox.Show("table1 changed");
};
alerttz.start();
DatabaseChangeAlert alert = new DatabaseChangeAlert("table2", GlobalResources.ConnectionString);
alert.DatabaseChangeEvent += (e, d) =>
{
MessageBox.Show("table2 changed");
};
alert.start();
Now my Problem is that when I change anything in table2 I do not get a notification, but when I do the same for table 1 I get a notification!
any ideas what the problem could be?
I also tried to only suscribe for table2...but it remain the same.
I've repeated your situation and wrote unit test (TwoTablesNotificationTest), but didn't find anything. It works fine for me. In this situation you could stop receive notifications from SqlDependency in case of destructor call of some DatabaseChangeAlert entity, because it has SqlDependency.Stop(connectionString) instruction. Thus, you have to call SqlDependency.Start after every SqlDependency.Stop to continue receiving events, but destructor is called automatically by garbage collector from parallel thread and it may cause this effect.
And I want to warn you - be careful using SqlDependency class because it has memory leak problem. For my project I used open source realization of SqlDependency - SqlDependencyEx. It is very easy to use:
int changesReceived = 0;
using (SqlDependencyEx sqlDependency = new SqlDependencyEx(
TEST_CONNECTION_STRING, TEST_DATABASE_NAME, TEST_TABLE_NAME))
{
sqlDependency.TableChanged += (o, e) => changesReceived++;
sqlDependency.Start();
// Make table changes.
MakeTableInsertDeleteChanges(changesCount);
// Wait a little bit to receive all changes.
Thread.Sleep(1000);
}
Assert.AreEqual(changesCount, changesReceived);
Hope this helps.
I have the following code to execute a SqlCommand against a database View:
public IEnumerable<PickNote> GetData()
{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["BTNInternalData_LiveEntities"].ConnectionString))
{
connection.Open();
using (var command = new SqlCommand(#"SELECT [PICKINGROUTEID],[CUSTOMER],[SALESNAME]
FROM [dbo].[PickScreenData] WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, [ACTIVATIONDATETIME])) = DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE())) or [EXPEDITIONSTATUS] = 3", connection))
{
// Make sure the command object does not already have
// a notification object associated with it.
command.Notification = null;
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
using (var reader = command.ExecuteReader())
{
var data = reader.Cast<IDataRecord>();
return data.Select(x => new PickNote
{
pickingRouteId = x["PICKINGROUTEID"].ToString()
}).ToList();
}
}
}
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
// do stuff
}
However, the dependency_OnChange method only gets called at the start of my application and doesn't do so again no matter if the data in my View changes. I've debugged SqlNotificationEventArgs and the Info is Invalid but I'm not sure why as the command query runs fine
Edit
I've changed the query so that it queries the table directly but SqlNotificationEventArgs.Info still says Invalid. Here is the new code:
public IEnumerable<PickNote> GetData()
{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["AXLive"].ConnectionString))
{
connection.Open();
using (var command = new SqlCommand(#"
SELECT PICKINGROUTEID, EXPEDITIONSTATUS
FROM [dbo].[WMSPICKINGROUTE]
WHERE (EXPEDITIONSTATUS <> 20)
AND (DATEADD(dd, 0, DATEDIFF(dd, 0, [ACTIVATIONDATETIME])) = DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
OR [EXPEDITIONSTATUS] = 3)", connection))
{
// Make sure the command object does not already have
// a notification object associated with it.
command.Notification = null;
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
using (var reader = command.ExecuteReader())
{
var data = reader.Cast<IDataRecord>();
return data.Select(x => new PickNote
{
pickingRouteId = x["PICKINGROUTEID"].ToString()
}).ToList();
}
}
}
}
WMSPICKINGROUTE is the table where my view was getting the data from before.
According to this MSDN page, you cannot use a SqlDependency against a select statement that references a view. That seems to be the problem. Rewrite your query to hit tables and it should work.
I was wondering if someone could help me out with this issue.
Basically I have a Web App, that searches a DB for a person based on an UID. After it finds the name, I open another db conn and search for their Managers email address.
However i'm getting the "Object reference not set to an instance" error, which i'm assuming something is null and it doesn't like it? that correct.
Here is my code.
public partial class Leaver : System.Web.UI.Page
{
string Managers_Name = null;
string Managers_Email = null;
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_SearchDB(object sender, EventArgs e)
{
SqlDataReader reader = null;
SqlConnection conn = null;
try
{
conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["App_NewStarterConnectionString"].ConnectionString);
{
conn.Open();
using (SqlCommand cmd =
new SqlCommand("SELECT * FROM dbo.tb_starters WHERE Payrol = #Payrol", conn))
{
cmd.Parameters.AddWithValue("#Payrol", Payrol.Value);
reader = cmd.ExecuteReader();
while (reader.Read())
{
Fname.Value = reader["FirstName"].ToString();
Lname.Value = reader["LastName"].ToString();
Payrol.Value = reader["Payrol"].ToString();
section.Value = reader["Section"].ToString();
Managers_Name = reader["Manager"].ToString();
}
}
}
}
catch (Exception ee)
{
throw ee;
}
finally {
GetManagersEmail();
if (reader != null)
reader.Close();
if (conn.State == ConnectionState.Open)
conn.Close();
}
}
protected void GetManagersEmail()
{
SqlDataReader reader_new = null;
SqlConnection conn_new = null;
try
{
conn_new = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["App_NewStarterConnectionString"].ConnectionString);
{
conn_new.Open();
using (SqlCommand cmd = new SqlCommand("SELECT Email FROM dbo.tb_starters WHERE FullName = #ManagersName", conn_new))
{
cmd.Parameters.AddWithValue("#ManagersName", Managers_Name);
while (reader_new.Read())
{
Managers_Email = reader_new["Email"].ToString();
Response.Write(Managers_Email);
}
}
}
}
catch (Exception ee)
{
throw ee;
}
finally
{
if (reader_new != null)
reader_new.Close();
if (conn_new.State == ConnectionState.Open)
conn_new.Close();
}
}
Did you get the reference for reader_new as you did in reader = cmd.ExecuteReader();
try with
reader_new = cmd.ExecuteReader();
However i'm getting the "Object reference not set to an instance" error, which i'm assuming something is null and it doesn't like it? that correct.
Correct. Performing an action on a NULL object throws that error.
Without the stack trace, this is a guess.
Possibly, your error is around here:
Fname.Value = reader["FirstName"].ToString();
Lname.Value = reader["LastName"].ToString();
Payrol.Value = reader["Payrol"].ToString();
section.Value = reader["Section"].ToString();
Managers_Name = reader["Manager"].ToString();
If one of these values is NULL, an Object reference not set to an instance would be thrown.
Don't assign null value to your SqlDataReader and SqlConnection at the begining just define them like
SqlDataReader reader;
SqlConnection conn ;
This might be the problem !!!