SqlDependency OnChange Not Firing - c#

This is the first time I've ever needed to use an SqlDependency so I am hoping that its a stupid mistake I've made.
The problem I'm having is that the OnChanged event doesn't fire when the sql table changes. No errors or anything just it doesn't fire.
Here is the code
public class SqlWatcher
{
private const string SqlConnectionString = "Data Source = CN-PC08\\DEV; Initial Catalog=DEP; User = sa; Password=******";
public SqlWatcher()
{
SqlClientPermission perm = new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);
perm.Demand();
SqlCommand cmd = new SqlCommand("SELECT [DataAvaliable], [RowNumber] FROM [dbo].[Trigger]", new SqlConnection(SqlConnectionString));
SqlDependency sqlDependency = new SqlDependency(cmd);
sqlDependency.OnChange += On_SqlBitChanged;
}
private void On_SqlBitChanged(object sender, SqlNotificationEventArgs sqlNotificationEventArgs)
{
SqlDependency dependency = (SqlDependency)sender;
dependency.OnChange -= On_SqlBitChanged;
// Fire the event
if (NewMessage != null)
{
NewMessage(this, new EventArgs());
}
}
public void Start()
{
SqlDependency.Start(SqlConnectionString);
}
public void Stop()
{
SqlDependency.Stop(SqlConnectionString);
}
public event EventHandler NewMessage;
And in my main window I have this
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
try
{
SqlWatcher sqlWatcher = new SqlWatcher();
sqlWatcher.Start();
sqlWatcher.NewMessage += On_NewMessage;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void On_NewMessage(object sender, EventArgs eventArgs)
{
MessageBox.Show("Message Received");
}
}
So the expected behaviour is that if I run the following sqlQuery a messageBox will be displayed saying "Message Received"
INSERT INTO [DEP].[dbo].[Trigger] Values(0,3)
Could anyone give me a hint on what to check/change?
I'm aware that only a subset of Sql features can be used in dependencies but I don't think I'm trying to do anything to fancy here.

I'm hoping that its a stupid mistake I've made.
Unfortunately (or fortunately?) you are making several mistakes.
First is you need to understand that Query Notifications will invalidate one query. So you will only be notified at most once and you have to re-subscribe again (re-submit the query) if you want to receive further notifications.
Next you need to understand that you will be notified for any reason, not only for changes. In your callback you must check the reason you're notified, which are passed in via the SqlNotificationEventArgs.
Next you need to understand asynchronous programming basic principles: if you subscribe for an event make sure you subscribe before the event can happen first time. Case in point: the On_SqlBitChanged can fire as soon as you submit the query. This should happen in the SqlWatcher.SqlWatcher constructor, but you subscribe to the sqlWatcher.NewMessage after the constructor runs. On_SqlBitChanged can be invoked between the constructor finishes before you hook up the NewMessage event callback in which case the notification is silently ignored.
If you want to use a service make sure you start it before you use it. You are using SqlDependency in SqlWatcher.SqlWatcher but you start it after that when you call SqlWatcher.Start().
Finally, if you want to be notified of changes on a query you have to submit the query. You are constructing the SqlCommand object, set up the notification and then... discard the object. Unless you actually submit the query, you did not yet subscribed to anything.
Suggestions for fix:
Make Start and Stop statics, call Start in application start up.
Make sure you subscribe to NewMessage before you submit the query
Actually submit the query (call SqlComamnd.ExecuteQuery())
Inspect the Info, Type and Source in the On_SqlBitChanged callback, if your submission contains an error this is the only way to learn (the SqlComamnd.ExecuteQuery() will succeed even if the notification request is invalid)
You must re-subscribe once you're notified of a change, execute the query again.
One more thing: don't invoke UI code in background callbacks. You cannot call MessageBox.Show("Message Received"); from a callback, you must route through the form main thread via Form.Invoke. YEs, I know that strictly speaking MessageBox.Show does work on a non-UI thread but you will soon move away from alert boxes to actually form interaction and then things will break.

Related

Correct way to update a GUI from a class in C#

I am looking for a way to update a GUI from a class that I want to be stand alone and not rely on the GUI. It is a network class consisting of both a listener and a client. This class can connect and then send/receive data. I would like this data to be able to be displayed using a GUI but not have any of the GUI related code within the class itself.
So in short the network class only knows of itself. The GUI knows of the network class.
This is where I would like to add the code
public void ReceiveBytes()
{
byte[] receivedPacket;
while (IsListeningForBytes)
{
receivedPacket = new byte[Packet.BUFFERSIZE];
try
{
int bytesRead = ClientSocket.Receive(receivedPacket, SocketFlags.None);
if (bytesRead > 0)
{
SocketObject.ProcessMessage(receivedPacket);
// Update GUI here after the message has been processed.
}
else
{
throw new Exception("No bytes read");
}
}
catch (Exception ex)
{
IsListeningForBytes = false;
Disconnect();
Console.WriteLine(ex.Message);
}
}
}
Edit: Sorry everyone I will try and make things clearer. I am using windows forms and for the sake of this exercise we'll say I have three different controls: a listbox, a combobox and a textbox, that will take the data dependant of what is sent. (My actual application has listboxes, combo boxes, checkboxes ect that will need to be updated).
I understand that I shouldn't reference the GUI from within my object, hence my question.
As for relevant code, I'm not sure what you would like to see.
I have read about eventhandlers and delegates but I'm unsure how to actually implement it in this case. I originally passed a GUI update method as an action to the class that was called when required but this seemed long winded and didn't specifically update the control that I wanted.
Thanks for your help so far.
It would be a violation of OOP to directly update your UI from your object.
Instead, implement an event to let the caller/user know something has happened, and make it their responsibility to update the UI.
Here's an example:
//added event, SomeDataObject is for you to create.
public event EventHandler<SomeDataObject> MessageProcessed;
public void ReceiveBytes()
{
byte[] receivedPacket;
while (IsListeningForBytes)
{
receivedPacket = new byte[Packet.BUFFERSIZE];
try
{
int bytesRead = ClientSocket.Receive(receivedPacket, SocketFlags.None);
if (bytesRead > 0)
{
SocketObject.ProcessMessage(receivedPacket);
// no UI update but fire an event
MessageProcessed?.Invoke(this, new SomeDataObject());
}
else
{
throw new Exception("No bytes read");
}
}
catch (Exception ex)
{
IsListeningForBytes = false;
Disconnect();
Console.WriteLine(ex.Message);
}
}
}
See:
Understanding events and event handlers in C#
or
https://msdn.microsoft.com/en-us/library/db0etb8x(v=vs.110).aspx
or
https://duckduckgo.com/?q=EventHandler+C%23&t=h_&ia=qa
update
So, how it works:
In you FooGUI class, you'll need to subscribe the event.
//so, your UI, can be a window, a form or ... console.
//I'll call your class BytesReceiver
public class FooGUI
{
BytesReceiver _receiver = new BytesReceiver();
//somewhere, in some function your listener has started
void Init()
{
//we added an event earlier, now attach a handler.
//a handler is a function, bound to some signature (as defined by the delegate)
//which will be executed when the event is triggered.
//so again; we bind a function to the event, which is invoked when the event is
//raised.
//keep in mind: the Invoke take place on the other thread; so the handler
//runs on that same thread.
//there is no magical polling taking place: it's just a
//function call (from receiver).
//note: there are various ways to bind a function: I'll use lambda here
_receiver.MessageProcessed += (sender,e) =>
{
//update GUI here.
}
//since there your while loop waits for a long time
//there must be some non-blocking operation, presumably on another thread.
_receiver.StartListening();
}
}

Working with an event handler - but not always.. (How do i...)

I'm quite new to C# and certainly OOP concepts.. so forgive the stupidity of my question.
I have a system I wish to communicate with, It has a number of commands that can be called with an associated response. (Communication is done via TCP/IP or Serial) (I implemented an Interface with SendMessage so that I can use multiple transport mechanisms)
I want to create a method for each command and then expose these, which is simple enough. The device also lets say 'broadcasts' messages as well which I want to act on, so I was using an event handler for this which works well..
At the moment in the event handler I catch OK and ERROR style messages, but ideally I would like to also be able to send the command from the above method and catch an error and return a bool value based on the command.
Can anyone think of a way I can do something like this and point me in the right direction?
Thanks
David
You can use helper to wait for event. Some ugly code from past:
public class ComWait
{
ManualResetEvent _waitEvent;
SomeEvent _eventHandler;
public ComWait()
{
_waitEvent = new ManualResetEvent(false);
_eventHandler = new SomeEvent(Watch);
}
void Watch()
{
_waitEvent.Set();
}
public bool Wait(int time = 3000)
{
_waitEvent.Reset();
SomeEvent += _eventHandler;
bool result = _waitEvent.WaitOne(time, false);
SomeEvent -= _eventHandler;
return result;
}
}
Usage is
ComWait wait = new ComWait();
if(!wait.Wait())
return; // timeout
// process
It will simply block synchronous method until event is rised or timeout occurs. It should be easy to add parameters: to unblock on specific event and to pass event handler parameters back to caller.
Otherwise I would simply have method inside communication class to use as a blocker:
readonly object _waitLock = new object();
public void Wait()
{
lock (_waitLock)
if (!Monitor.Wait(_waitLock, 3000))
throw new TimeoutException("No communications");
}
Signal at same time as you rise event:
lock (_waitLock)
Monitor.PulseAll(_waitLock);

How to return data from void function?

So, around a week ago I asked a question about activex and UDP. Here it is:
C# UDP Socket client and server
Now, I created two applications, one (the sender) to send pre-defined strings via UDP. The other is activex component that is called from a webpage, and it's thread is working in the background. Once an UDP message arrives, then it's doing it's stuff (writing in database, writing in log.txt, and so on).
The last thing i need is to return data (it's yet to be said if it will be string or something else). However, the method in the activex which is called must be a void, because if it's made to be string, the threading wont work, and only the first message will arrive.
My question is, how to do that? How to return data from a void function? For example, the web app now is calling the activex DLL like this:
ClassLibrary1.Class1 activex = new ClassLibrary1.Class1();
activex.StartThread();
And the StartThread() calls the listening thread and it's working in the background, and once UDP msg arrives, its doing some stuff like i said above.
How can i return value with the threads (events) and the web app will catch it and use it?
Thanks a lot.
You can use events (which implement the Observable pattern) to alert any listener that a new message has arrived:
public class NewMessageArgs : EventArgs
{
public string Message { get; private set; }
public NewMessageArgs(string message)
{
Message = message;
}
}
public class ActiveXComponent
{
public event EventHandler<NewMessageArgs> OnMessage;
public void StartThread()
{
while (true)
{
//do stuff
//raise "message received" event
if (OnMessage != null)
OnMessage(this, new NewMessageArgs("hi"));
}
}
}
You can then listen to these events like so:
ActiveXComponent activex = new ActiveXComponent();
activex.OnMessage += ProcessMessage;
activex.StartThread();
public void ProcessMessage(object sender, NewMessageArgs args)
{
var msg = args.Message;
//process
}
Basically you have to store some data in a spot where you can access it from both places (from the thread, and from the place where you started the thread). So you have a couple of options from the top of my head.
Store it in a database
Create a specific object (whatever type you need), and store it in a place where it is accessible from both places. For example, a singleton. A simpler better solution is to create a property on your ClassLibrary.Class1 class: set it from within the Class1-class, and get it from the place where you created an instance of your Class1-class.
Add an event to your Class1-class which fires when it is finished doing its job. And add some data to the EventArgs.
I'm assuming here you get notified when your thread is done doing whatever it is doing.
Edit: added events
The threading function can change the fields values of the class and you can access those fields, also your thread can fire events that other classes can subcribe to and then act on it.
Class1
{
private string value;
public string Value{get{return value;} set{value=value; FireTheEvent();}}
}

How to change a GUI control state by the event handler

Request description
I'm handling a project which need to call a background process to read some data from database. The get data button of the GUI will turn to gray during this time and turn to enable after the data arrived. If there is any exception throw from the background process the button need to turn to enable to make sure the user could send another request.
Problem description
One get data failed event is added to the background process to let the UI thread notice there is a exception encountered by the get data process. But the state of the button can't be changed in the event handler function due to there are running in the difference thread.
Relative codes snippets
Back ground thread code
class DataProcessService
{
public static SingletonInstance {get;set;} //Omit the codes implement the singleton pattern
public event EventHandler GetDataFailed;
private void FireGetDataFailed()
{
if(GetDataFailed != null) GetDataFailed(this, null);
}
// in some function
try
{
// do some get data process
}
catch(SqlException ex)
{
FireGetDataFailed();
}
}
GUI codes
//In the init function subscribe to the event
DataProcessService.SingletonInstance.GetDataFailed += new Eventhandler(GetDataFailedEventHander_EnableButtonState);
private void GetDataFailedEventHander_EnableButtonState(object s, EventArgs e)
{
btnGet.Enabled = true; //There will be a exception
}
Questions
How to change the UI control from the event hander in .net 3.5? In .net 4.0 may be I could use TPL to handle this. Any suggestions will be appreciated, thanks.
Development environment
VS2008, .net 3.5
You will have to invoke it back onto the UI thread
private void GetDataFailedEventHander_EnableButtonState(object s, EventArgs e)
{
base.Invoke((Action)delegate { btnGet.Enabled = true; });
}

Mandatory Event not subscibed

Problem:
I am working on a application where in for some time consuming operation, i am supposed to show a progress bar on a form (WinForm) with a cancel button. So obviously i am using BackgroundWorker thread for it. Below is the code which simulates roughly of what i am trying to achieve.
namespace WindowsFormsApplication1
{
public delegate void SomeDelegateHandler();
public partial class Form1 : Form
{
public event SomeDelegateHandler DoSomeAction;
BackgroundWorker bgWorker;
public Form1()
{
InitializeComponent();
bgWorker = new BackgroundWorker();
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
}
void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
//Some logic code here.
for (int i = 0; i < 100; i++)
{
DoSomeAction();
}
}
private void Form1_Shown(object sender, EventArgs e)
{
if (DoSomeAction != null)
bgWorker.RunWorkerAsync();
else throw new EventNotSubscribedException();//Is this a valid style??
}
}
public class EventNotSubscribedException : ApplicationException
{
//Some custom code here
}
}
My Solution
As per the above code, as soon as the form is displayed to the user (OnShown event) i am starting the backgroundworker thread. This is because, the user need not to initiate any action for this to happen. So onshown does time consuming operation job. But the issue is, as i have shown above, the main time consuming job is executed on other class/component where it is kind of tight bounded too (legacy code: cant refactor). Hence i have subscribed to the event DoSomeAction in that legacy code class which launches this form.
Doubt/Question:
Is it valid to throw exception as shown above? (Please read my justification below).
Justification:
The OnShown event does check for null on event handler object. This is because, to make this form usable, the event has to be subscribed by the subscriber (usage code), then only it shall work. If not, then the form just displays and does noting at all and usage code may not know why it is happenings so. The usage code may assume that subscribing to the event is option just like button click events per say.
Hope my post is clear and understandable.
Thanks & Happy Coding,
Zen :)
Do you mean that you need to throw an exception to the caller of the form? Is it called using showDialog or Show?
BTW, I dont prefer to generate an exception from an event. Rather it would be rather nice to keep it such that it returns from the place with some status set on the Form class.
for instance, I would prefer using
IsEventSubscribed = false
this.Close()
rather than EventNotSubscribedException
BTW, One problem I can see in the code, when the bgWorker_DoWork is called, you should check DoSomeAction to null, because otherwise it might cause NullReferenceException.
Preferably,
Start the run the RunWorkerAsync from Form_shown
Check Delegate to null in DoWork, if it is null, do not call DoSomeAction otherwise call it.
On RunWorkerCompleted of the BackgroundWorker, close the form.
Let me know if you need anything more.
I would suggest making the consuming code construct the BackgroundWorker and pass it to the form's constructor. You can do a null test in the constructor and side-step this whole issue. Alternatively, take the delegate as a constructor argument instead. I mean, how likely is it that the consuming code will need to change the worker delegate mid-operation?
Another approach is to have the dialog monitor a task, instead of having a dialog control a task (as you have here). For example, you could have an interface like this:
public interface IMonitorableTask {
void Start();
event EventHandler<TData> TaskProgress;
}
Where TData is a type that provides any information you might need to update the dialog (such as percent completed).
The downside to this is that each task needs to be a type of its own. This can lead to very ugly, cluttered code. You could mitigate that issue somewhat by creating a helper class, something like:
public class DelegateTask : IMonitorableTask {
private Action<Action<TData>> taskDelegate;
public event EventHandler<TData> TaskProgress;
public DelegateTask(Action<Action<TData>> taskDelegate) {
if (taskDelegate == null)
throw new ArgumentNullException("taskDelegate");
this.taskDelegate = taskDelegate;
}
protected void FireTaskProgress(TData data) {
var handler = TaskProgress;
if (handler != null)
handler(this, data);
}
public void Start() {
taskDelegate(FireTaskProgress);
}
}
Then your task methods become factories:
public IMonitorableTask CreateFooTask(object argument) {
return new DelegateTask(progress => {
DoStuffWith(argument);
progress(new TData(0.5));
DoMoreStuffWith(argument);
progress(new TData(1));
});
}
And now you can easily(*) support, say, a command-line interface. Just attach a different monitor object to the task's event.
(*) Depending on how clean your UI/logic separation already is, of course.

Categories