Can SQL Server push a message to a program? - c#

Can SQL Server push message to a program which listens to SQL Server?
For example:
There is a program A, listening for SQL Server. SQL Server will view a table named B, when B has some data, SQL Server will get the data and push it to A.

Yes, it's possible, see How to run a program from SQL?.
But, as that post states, there are a lot of reasons not to do so. SQL Server was written to be queried, so it will be a lot more efficient answering queries than pushing them.

You can use SqlDependecy (class Details) to detect changes in tables/views. This does require Enabling Query Notifications.
void Initialization()
{
// Create a dependency connection.
SqlDependency.Start(connectionString, queueName);
}
void SomeMethod()
{
// Assume connection is an open SqlConnection.
// Create a new SqlCommand object.
using (SqlCommand command=new SqlCommand(
"SELECT ShipperID, CompanyName, Phone FROM dbo.Shippers",
connection))
{
// 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(OnDependencyChange);
// Execute the command.
using (SqlDataReader reader = command.ExecuteReader())
{
// Process the DataReader.
}
}
}
// Handler method
void OnDependencyChange(object sender,
SqlNotificationEventArgs e )
{
// Handle the event (for example, invalidate this cache entry).
}
void Termination()
{
// Release the dependency.
SqlDependency.Stop(connectionString, queueName);
}
To use SqlDependency, Service Broker must be enabled for the SQL Server database being used, and users must have permissions to receive notifications. Service Broker objects, such as the notification queue, are predefined.

Are you looking for some kind of SqlServerNotifications | MSDN? For me that did not work because it requers some Configuration that we were not able to implement ( security reasons ) ... so i implemented my own notification layer with my own TCP network wrapper. When one client updates the database, it sends to all other clients a message with ID and table name, and the Client will update the entry by it self. Its not easy to implement and requers a lot of desgin.

Related

C# Update Application Based on Updates in DB

I'm creating a chatting application in C# where clients can chat privately, however I’m struggling to update the messages based on changes within the DB (sql-server).
Should I create a constant running thread which requests data after the last message id outputted? I think this may be inefficient, is there other methods? Or could you recommend a better method?
public void Display_Messages(dynamic listbox, int conversation_id)
{
Connection _connection = new Connection();
_connection.conn.Open();
string sql = "SELECT userId, text, messageId FROM message WHERE conversationId =" + conversation_id + ";"; // Update Later to use PS
dynamic command = new SqlCommand(sql, _connection.conn);
dynamic data_reader = command.ExecuteReader();
while (data_reader.Read())
{
listbox.Items.Add(data_reader.GetValue(0) +":"+data_reader.GetValue(1));
}
data_reader.Close(); command.Dispose(); _connection.conn.Close();
}
You can use SQL Server's broker service which notifies your custom data changes, but there must not be too many listeners on it for performance considerations. The polling mechanisms usually are not efficient enough and put a constant load on the system even when there is no new data to be notified.
You can find all the information you need to use the broker service online.

Accessing APIs in the same solution

I am developing solution where there are three webapi projcets.
Each of them is secured with JWT tokens mechanism.
So far webapis had not need to communicate. Finally they will be deployed on azure separetly and they will be using the same database.
I could generate a token with infinite lifespan and store it somewhere in the database, but something tells to me this is not right way to solve this issue.
Any help will be appreciated.
Question: How to allow them to communicate other way than generating a token with infinite lifespan?
Sounds like a use case for SQL Dependencies. An SQL dependency allows you to subscribe to an event that gets triggered when the result of a command differs. Something like so:
// I'll assume that a connection is already open
using (var command = new SqlCommand("SQL Command goes here")
{
var dependency = new SqlDependency(command);
dependency.OnChange += (object sender, SqlNotificationEventArgs e) =>
{
// Handle OnChange here
Console.WriteLine(e.Info);
}
// You can do all the things with the SQL Command here as you normally could
// for example execute it if it's a SELECT and read data
}
Be careful when using SQL dependencies as they're a bit more time consuming/ expensive as one would think, so try to keep them to a minimum

alternate options for infinite loop

We are running one third party application which uses C#, SQL SERVER. We have created one other application which prints the pass.
Basically it does continuous checking of new entry from third party application in one of the table on remote database. If new entry is present then it prints pass. Accessing network database in such way is not good way and also sometimes application hang.
Instead of continuous loop, I am searching for some other way like: As the new entry comes, it trigger my application for print. Or any other good way to implement.
What you are looking for is the SqlDependency that can help you in
listening to the OnChange event.
Example from msdn:
void Initialization()
{
// Create a dependency connection.
SqlDependency.Start(connectionString, queueName);
}
void SomeMethod()
{
// Assume connection is an open SqlConnection.
// Create a new SqlCommand object.
using (SqlCommand command=new SqlCommand(
"SELECT ShipperID, CompanyName, Phone FROM dbo.Shippers",
connection))
{
// 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(OnDependencyChange);
// Execute the command.
using (SqlDataReader reader = command.ExecuteReader())
{
// Process the DataReader.
}
}
}
// Handler method
void OnDependencyChange(object sender,
SqlNotificationEventArgs e )
{
// Handle the event (for example, invalidate this cache entry).
}
void Termination()
{
// Release the dependency.
SqlDependency.Stop(connectionString, queueName);
}
Check it out: http://msdn.microsoft.com/en-us/library/62xk7953.aspx
If any user subsequently changes the underlying data, Microsoft SQL
Server detects that there is a notification pending for such a change,
and posts a notification that is processed and forwarded to the client
through the underlying SqlConnection that was created by calling
SqlDependency.Start. The client listener receives the invalidation
message. The client listener then locates the associated SqlDependency
object and fires the OnChange event.
let me just sum up the data:
you need to give us more information for a more intelligent help here bu basically you can:
Use a timer: that way you are not in an infinite loop and you don't check every few ticks the 3rd party. you can be more sophisticated even and make the time interval grow and shrink according to data changes found or not
if you can change the 3rd party so it'll send events or signal when it has new data then you can use that and register to the events and save a lot of process time
if you can change the DB add triggers and use them to know then new data come and thus you don't need nothing more then that

SQLDependency + Service Broker

I'm using SqlDependency to get notification when data in some table are changed.
private void subscribeBroker()
{
using (var conn = new SqlConnection(connString))
{
conn.Open();
var cmd = new SqlCommand("SELECT text FROM dbo.Test");
cmd.Connection = conn;
var dependency = new SqlDependency(cmd);
dependency.OnChange += dependency_OnChange;
SqlDependency.Start(connString);
cmd.ExecuteNonQuery();
}
}
void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
//Do something...
subscribeBroker();
}
It is working but I have some questions.
1) I didn't find a way how to get information which row was changed. I need to read all data from entire table to see what is different. Is there a way how to get this information? (primary ID, or something) Maybe to use different approach than SqlDependency?
2) What if "somebody" changing data very fast. It is possible that some changes will not being notified? (I'm concerned about time between notification and time when I subscribe it again.
Thank you.
About 1- query notification informs you about the fact, that something is changed. If you want to get what was changed since last time- you could probably use timestamp column.
About 2- query notification informs you about changes and then is dropped. then you again subscribe for notification again. that mean- time between dropping and creation of notifications is that time in which notification about changes is not send.
Query notifications is more for the situations, when your data is not changing frequently. For example- some cashed classification values. So- you subscribe for changes in some table, wait for changes and at the time they happen you get latest version of data. Should consider that query notification also uses server resources, so if you have huge table and want to get changes on some small subset of data, a lot of queries can be affected in terms of performance (something like indexed view).
If you need to take some action based on changed data and each change is important, then i would guess that trigger + service broker could be more effective. Or, depending on your needs, Change Data Capture.

SQL Server Notifications - My OnChange does not fire

I would like to make use of SQL Server notifications to capture insert events at my database within a winforms app. I am attempting to use the SQLDependency object. The MSDN articles make this seem pretty straight forward. So I have created a little example application to give it a try. The event only seems to fire as I enter my application the first time(MessageBox appears). Inserting data into the table does not raise the OnChange event it would seem. Can someone tell me what I'm missing? Thanks!
public Main()
{
InitializeComponent();
var check = EnoughPermission();
SqlDependency.Stop(constr);
SqlDependency.Start(constr);
if(connection == null)
{
connection = new SqlConnection(constr);
}
if(command == null)
{
command = new SqlCommand("Select ID, ChatMessage FROM dbo.Chat",connection);
}
connection.Open();
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
command.ExecuteReader();
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
MessageBox.Show("Change!");
}
While I was working in the implementation of query notification, I got the exact problem. I checked all configurations, code pieces, and even TCP settings, but nothing helped. Then, I figured out the following query to run on database and it solved my problem. Maybe you can try it.
ALTER AUTHORIZATION ON DATABASE::[Your DB] TO sa;
Your first notification is the only notification you'll get. Query Notifications are not a subscription for changes, once a notification is fired it is also invalidate. You are supposed to re-submit a new notification subscription.
If your query is notified immedeatly it means you did not get a notification for a change, but one for an invalid query. Check the values of the SqlNotificationEventArgs argument you receive. Check the Info to be Insert/Update/Delete, check the Source to be Data, check the Type to be Change.
Have a look at the Watcher Application example to better understand how you are supposed to re-subscribe when notified. For a better understanding of how the Query Notifications work, see The Mysterious Notification.

Categories

Resources