I've this piece of code in my page, but it don't run when i make changes in the database, what could be the problem.
This starts well, when i load the page this executes the function twice, but if i send a message to the database this doens't execute.
$(function () {
var chat = $.connection.chatHub;
chat.client.allTalks = function () {
refresh();
};
$.connection.hub.start();
refresh();
});
SERVER SIDE (HUB):
[HubName("chatHub")]
public class ChatHub : Hub
{
public static void AllTalks()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
context.Clients.All.allTalks();
}
}
HANDLER
...
using (SqlCommand command = new
SqlCommand(#"SELECT * FROM [dbo].[chat_talks]", connection)) {
//CONTENT
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
...
}
public void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
ChatHub.AllTalks();
}
GLOBAL.ASAX
protected void Application_Start(object sender, EventArgs e)
{
SqlDependency.Start(ConfigurationManager.ConnectionStrings["ProjectSellerConnection"].ConnectionString);
}
First off, it is redundant to have your first line in your server-side code. There is no need to call for a hubContext inside the Hub. You can just do:
public static void AllTalks()
{
Clients.All.allTalks();
}
I would suggest, perhaps foolishly, to not use SQL Dependency. I would instead suggest using the following technique of calling SignalR (specifically, it will call the client functions):
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
hubContext.Clients.All.allTalks();
You can call this in, for example, actions in MVC and WebAPI Controllers, thus meaning if you've done any database updates in those actions, you can subsequently call clients using this methodology. I know it's not as fancy as SQL Dependency, and perhaps not the answer your looking for, but it will solve your problem - since it appears the problem seems to be with SignalR detecting the database changes.
In other words, this methodology will work, but it's probably not the precise one you are hoping for.
Related
I have an ASP.NET Web Forms Page with the following code:
public partial class MyAspNetWebFormPage : System.Web.UI.Page{
protected void Page_Load(object sender, EventArgs e){
ClearRedisCache("RedisCacheConnectionString_01");
ClearRedisCache("RedisCacheConnectionString_02");
}
private void ClearRedisCache(string redisConnectionString){
var serverName = redisConnectionString.Split(',')[0];
using (var redis = ConnectionMultiplexer.Connect(redisConnectionString)){
var server = redis.GetServer(serverName);
server.FlushAllDatabases(CommandFlags.None);
redis.Close(true); // this was added as an effort to fix the problem but doesn't work
// Another effort to make it work
// Added after receiving the error
do {
Thread.Sleep(1000);
} while (redis.IsConnected);
}
}
}
When I run this on my local box it seems to work perfectly fine. However, when I run it in our Azure Environment it throws an exception with the following message:
A blocking operation was interrupted by a call to WSACancelBlockingCall
Other examples that I've seen are caching the connection and keeping it open. Is that how I'm suppose to implement redis cache?
This code is executed from an Admin Dashboard that is completely disconnected from the Consumer Site. The Admin Dashboard doesn't use Redis Cache other than to clear it.
Any ideas are greatly appreciated. Thank you in advance.
Looking into this further and playing with the settings here's what worked for me:
public partial class MyAspNetWebFormPage : System.Web.UI.Page{
protected void Page_Load(object sender, EventArgs e){
ClearRedisCache("RedisCacheConnectionString_01");
ClearRedisCache("RedisCacheConnectionString_02");
}
private void ClearRedisCache(string redisConnectionString){
string securityProtocol = (SecurityProtocol)Enum.Parse(typeof(SecurityProtocol), securityProtocol);
var options = ConfigurationOptions.Parse(redisConnectionString);
options.SslProtocols = System.Security.authentication.SslProtocols.Tls12;
options.Ssl = true;
options.AllowAdmin = true;
options.AbortOnConnectFail = false;
var serverName = redisConnectionString.Split(',')[0];
using (var redis = ConnectionMultiplexer.Connect(options)){
var server = redis.GetServer(serverName);
server.FlushAllDatabases(CommandFlags.None);
}
}
}
I have strange problem and question about using SqlDependency class in a normal Asp.net MVC application
I have standard controller with code:
public ActionResult Index()
{
RegisterNotification();
return View();
}
public void RegisterNotification()
{
var cs = ConfigurationManager.ConnectionStrings["TestDb"].ConnectionString;
var sql = #"Select Data From dbo.TestTable";
using (var conn = new SqlConnection(cs))
{
conn.Open();
using (var cmd = new SqlCommand(sql, conn))
{
cmd.Notification = null;
var sqlDependency = new SqlDependency(cmd);
sqlDependency.OnChange += SqlDependency_OnChange;
cmd.ExecuteNonQuery();
}
}
}
public void SqlDependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
// call some SignalR method here and re-register notification
RegisterNotification();
}
}
In Global.asax is SqlDepndency initialize (on start and end methods)
Well, in first request everything working great, but after some refresh(full request) SqlDependency_OnChange calling twice and next refresh calling four times and etc.
In console application this code works fine.
Is there something wrong with my code?
(Using Sql 2012 and asp.net MVC 5.2.3 and VisualStudio IISExpress dev server)
Thanks
I think what you'll want to do is create a Singleton that will handle the SqlDependency notifications. Every time someone makes a request, a new instance of your controller is being created, which registers for new notifications. When you're getting multiple notifications, I think you'll find that it's different instances of your controller getting notified.
There's a great example of this here
In my current setup, i have an ASP.NET 5 vNext project running.
I have setup SignalR Server 3.0.0-rc1-final and i am able to connect to my hub through my webinterface:
var visitorHub = $.connection.visitorsHub;
visitorHub.client.visitorEvent = function (message) {
$("#visitorinfo").append("<li>" + message + "</li>");
};
$.connection.hub.start().done(function () {
visitorHub.invoke("listenToEvents", "TestID");
});
So we are listening on visitorEvent from the hub and visitorEvent is called when listenToEvents is invoked.
My challenge come now, that i'm trying to notify from within the ASP.NET application. Using the build in IoC an SqlDependency is used to listen to events in the SQL server. Again this is working as intended, but when i'm trying to invoke the hub through it's HubContext nothing happens.
I have injected the IConnectionManager and able to get hold of my HubContext using:
var context = this.manager.GetHubContext<VisitorsHub>();
but when i do the following:
context.Clients.All.visitorEvent("2");
nothing happens.
I'm not sure why nothing happens and how i'm going to debug this?
My VisitorHub code is:
public class VisitorsHub : Hub
{
public async Task ListenToEvents(string visitorId)
{
this.NotifyVisitorListeners();
}
public void NotifyVisitorListeners()
{
this.Clients.All.visitorEvent("Event");
}
}
You can enable client side logging via:
$.connection.hub.logging = true;
$.connection.hub.start();
or without generated proxy:
var connection = $.hubConnection();
connection.logging = true;
connection.start();
Otherwise when using invoke (method without a proxy), methods aren't renamed to camelCase, but remain as they are, in your case CamelCase.
To overcome this you can simply rename method name on either end, or add HubMethodName decorator in your backend:
[HubMethodName("listenToEvents")]
public async Task ListenToEvents(string visitorId)
{
this.NotifyVisitorListeners();
}
I'm building an application that uses a WCF client to retrieve data from my server.
I want my call to the service to be asynchronous because many of them need to change the UI and I don't want to lose responsiveness from my app.
I tried using *Completed and *Async:
ServiceUserClient client = new ServiceUserClient();
client.FindUserCompleted += delegate(object sender, FindUserCompletedEventArgs e)
{
// here e.Result always fails
};
client.FindUserAsync(text);
Inside the *Completed delegate I always get an error (Connection closed by remote host: I enabled every logging I could find but I still don't understand why I get these errors)
Synchronous calls always work.
I have a class that handles all the calls to the service.
Is there a way to have syncronous calls inside something like a threaded class?
Are you setting the client side bindings to match what the server accepts?
You should also try testing it with the WCF test client (normally under %Program Files%\Microsoft Visual Studio 10.0\Common7\IDE\WcfTestClient.exe). If the test client works then check the bindings.
Is your call even getting to the server? I've had similar errors happen when serializing the response from the server to the client, so you might want to check for that. If you get to your server then the bindings are not the problem but rather there is a serialization problem. Do you have "sets" on the data model properties that are trying to get deserialized on the server?
I know this is no answer but I haven't been here enough to be allowed comments...and I've been where you are, totally frustrating.
I ended up creating my own async methods using BackgroundWorker this way (probably not the best way but it works):
// this is the click event on my search button
private void FindUser_Click(object sender, EventArgs e)
{
this.UserListSearch.Enabled = false;
this.UserListSearch.Items.Clear();
Model.FindUser(FindText.Text.ToUpper(), userlist =>
{
foreach (User u in userlist)
{
ListViewItem item = new ListViewItem(u.UserName);
item.Name = u.UserName;
item.SubItems.Add(u.Description);
this.UserListSearch.Items.Add(item);
}
this.UserListSearch.Enabled = true;
});
}
// this is the function I call when I need async call
public void FindUser(string text, Action<User[]> callback)
{
CreateBackgroundWorker<User[]>(() =>
{
ServiceUsersClient client = new ServiceUsersClient();
var results = client.FindUser(text);
client.Close();
return results;
}, callback);
}
// this is my utility function to create a bgworker "on demand"
private void CreateBackgroundWorker<T>(Func<T> dowork, Action<T> callback)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (sender, args) =>
{
T result = dowork.Invoke();
(callback.Target as Form).Invoke(callback, result);
};
worker.RunWorkerAsync();
}
I have a C# program that queries the SQL Server database for some values.
Currently the application queries the database every minutes to make sure that the table is up to date.
What I would like to be able to do is that the query is only done when the database has been changed / updated. How do I notify my program when something has been updated in the database?
Thanks
Polling database is not very elegant solution.
SqlDependency from ADO.NET will be useful in your case. It does not use polling but notification mechanism. The notifications are provided by Service Broker in your database, so will need to enable this service in your databse. The OnChange event will raise when specified table changes(update, delete, insert..)
Here is an example how to use SqlDependency:
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);
}
from http://msdn.microsoft.com/en-us/library/62xk7953.aspx
Here is how to enable Service Broker(note that you will have exclusiveness on the database to do that - best do it after restart of the sql server):
http://blogs.sftsrc.com/stuart/archive/2007/06/13/42.aspx(Broken link)
Possible alternative link: http://technet.microsoft.com/en-us/library/ms166086(v=sql.105).aspx
If you are on SQL Server 2005 and above, you can consider using the SqlDependency object.
It represents a query notification dependency between an application and an instance of SQL Server 2005.
An application can create a SqlDependency object and register to receive notifications via the OnChangeEventHandler event handler.
Refer this link on MSDN for more information
However, do note the caveat that MS puts against its use. It is advised to have a caching layer and then use SQLDependency in coordination with that layer .
SqlDependency was designed to be used in ASP.NET or middle-tier services where there is a relatively small number of servers having dependencies active against the database. It was not designed for use in client applications, where hundreds or thousands of client computers would have SqlDependency objects set up for a single database server.
To get a notify when some record is updated, avoid the application to query the table you cab use TableDependency component (in your specific case SqlTableDependency). Here is an example:
public partial class Window1 : Window
{
private IList<Stock> _stocks;
private readonly string _connectionString =
"data source=.;initial catalog=myDB;integrated security=True";
private readonly SqlTableDependency<Stock> _dependency;
public Window1()
{
this.InitializeComponent();
this.McDataGrid.ItemsSource = LoadCollectionData();
this.Closing += Window1_Closing;
var mapper = new ModelToTableMapper<Stock>();
mapper.AddMapping(model => model.Symbol, "Code");
_dependency = new SqlTableDependency<Stock>(_connectionString, "Stocks", mapper);
_dependency.OnChanged += _dependency_OnChanged;
_dependency.OnError += _dependency_OnError;
_dependency.Start();
}
private void Window1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
_dependency.Stop();
}
private void _dependency_OnError(object sender, TableDependency.EventArgs.ErrorEventArgs e)
{
throw e.Error;
}
private void _dependency_OnChanged(
object sender,
TableDependency.EventArgs.RecordChangedEventArgs<Stock> e)
{
if (_stocks != null)
{
if (e.ChangeType != ChangeType.None)
{
switch (e.ChangeType)
{
case ChangeType.Delete:
_stocks.Remove(_stocks.FirstOrDefault(c => c.Symbol == e.Entity.Symbol));
break;
case ChangeType.Insert:
_stocks.Add(e.Entity);
break;
case ChangeType.Update:
var customerIndex = _stocks.IndexOf(
_stocks.FirstOrDefault(c => c.Symbol == e.Entity.Symbol));
if (customerIndex >= 0) _stocks[customerIndex] = e.Entity;
break;
}
this.McDataGrid.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
{
this.McDataGrid.Items.Refresh();
}));
}
}
}
private IEnumerable<Stock> LoadCollectionData()
{
_stocks = new List<Stock>();
using (var sqlConnection = new SqlConnection(_connectionString))
{
sqlConnection.Open();
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = "SELECT * FROM [Stocks]";
using (var sqlDataReader = sqlCommand.ExecuteReader())
{
while (sqlDataReader.Read())
{
var code = sqlDataReader
.GetString(sqlDataReader.GetOrdinal("Code"));
var name = sqlDataReader
.GetString(sqlDataReader.GetOrdinal("Name"));
var price = sqlDataReader
.GetDecimal(sqlDataReader.GetOrdinal("Price"));
_stocks.Add(new Stock { Symbol = code, Name = name, Price = price });
}
}
}
}
return _stocks;
}
The event handler is triggered for every INSERT UPDATE or DELETE operation done on the table, reporting you the modified value. So, in case you are interested to keep your C# Datatable up to date, you simple can get the fresh data from the event handler.
What I would like to be able to do is that the query is only done when the database has been changed/updated.How do i notify my program when some thing updated in database.
There isn't any means of the database pushing notifications to the application. The application needs to poll the database to check for updates, and then deal with the updates appropriately.
If by "updates to the database" you mean any update by any application, you're out of luck: it's not doable.
If, however, you mean changes made by your app, it's easy: every time you update the DB raise and event and have handlers respond to the event.