I have a problem when using SQLDependency and SignalR Hub. When a connection with the hub is started, the SQLDependency's OnChange event is always firing even though there are no changes in the database.
Here is my code that contains SQLDependency
public List<NotifCenterModel> countNewTransaksi()
{
List<NotifCenterModel> ncms = new List<NotifCenterModel>();
command = new SqlCommand(#"SELECT Edolpuz_DB.dbo.TABEL_NOTIF_CENTER.NAMA_TABEL,Edolpuz_DB.dbo.TABEL_NOTIF_CENTER.JUMLAH_NOTIF FROM Edolpuz_DB.dbo.TABEL_NOTIF_CENTER",connect);
try
{
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if(connect.State == ConnectionState.Open)
connect.Close();
connect.Open();
reader = command.ExecuteReader();
while (reader.Read())
{
ncms.Add(new NotifCenterModel(reader[0].ToString(), int.Parse(reader[1].ToString())));
}
return ncms;
}
catch { return null; }
finally { connect.Close(); }
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
TransHub.Show();
}
and in my Hub the code is like this
public class TransHub : Hub
{
public static void Show()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<TransHub>();
context.Clients.All.displayStatus();
}
}
and here is my javascript
$(function () {
// Proxy created on the fly
var job = $.connection.transHub;
// Declare a function on the job hub so the server can invoke it
job.client.displayStatus = function () {
// alert("test");
getData();
};
// Start the connection
$.connection.hub.start().done(function () {
getData();
}).fail(function (e) {
alert(e);
});
});
function getData() {
$.ajax({
url: server + '/Admin/GetNotifikasi/',
type: 'GET',
dataType: 'json',
success: function (data) {
for (var i = 0; i < data.length ; i++)
{
if (data[i].nama_tabel == "TABEL_TRANSAKSI")
{
$('#notifTrans').text(data[i].jumlah_notif);
}
else if (data[i].nama_tabel == "TABEL_KONF_BAYAR")
{
$('#notifBayar').text(data[i].jumlah_notif);
}
else if (data[i].nama_tabel == "TABEL_TESTI")
{
$('#notifTesti').text(data[i].jumlah_notif);
}
else if (data[i].nama_tabel == "TABEL_KUSTOM_ORDER")
{
$('#notifKustom').text(data[i].jumlah_notif);
}
}
}
});
}
When in connection.hub.start().done I call getData(), it will constantly fire and produce an infinite loop, but when I don't call getData() it doesn't fire the event when data in table changes. How can this be fixed?
In dependency_OnChange, you need to check e.Type. If it's != SqlNotificationType.Change, then the handler was called for some reason other than a data change. The subscription itself likely failed.
According to this site (https://learn.microsoft.com/en-us/previous-versions/aewzkxxh(v=vs.90)), the table name in query must be two-part name, like [dbo].[TABEL_NOTIF_CENTER].
The projected columns in the SELECT statement must be explicitly stated, and table names must be qualified with two-part names. Notice that this means that all tables referenced in the statement must be in the same database.
[]'s
Related
I tried to upgrade CefSharp from Version 69.0.0.0 to 79.1.36.
I could not get the Javascript interaction working.
The registration changed from
this.Browser.RegisterJsObject
to
this.Browser.JavascriptObjectRepository.Register
according to https://github.com/cefsharp/CefSharp/issues/2990.
When I execute EvaluateScriptAsync, I get a response back with Status Canceled.
Trying to understand how to implement it correctly, I examined the CefSharp.WpfExample and noticed that the Javascript functionality in the example WPF application does not work either.
The Execute Javascript (asynchronously) does not do anything when clicking the Run button.
The Evaluate Javascript (Async) returns:
Uncaught ReferenceError: bound is not defined # about:blank:1:0
Did the Javascript functionality break in the latest release?
Update
Here is how it is used in our code.
This is the registration
public void RegisterJavaScriptHandler(string name, object handler)
{
try
{
CefSharpSettings.LegacyJavascriptBindingEnabled = true;
this.Browser.JavascriptObjectRepository.Register(name, handler, false, new BindingOptions() { CamelCaseJavascriptNames = false });
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
This is the EvaluateScriptAsync part
public void InitializeLayers()
{
try
{
int count = _mapLogic.Layers.Count();
foreach (WMSLayer layer in _mapLogic.Layers)
{
if (!_loadedLayers.Contains(layer))
{
var script = string.Format("addWMSLayer('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}', '{8}', '{9}')",
layer.ProviderCode.Url, layer.AttributionText, layer.AttributionHref,
layer.Layer, layer.FormatCode.Format, layer.ServerType, layer.Res1, layer.Res2, layer.Res3, layer.Res4);
var response = this.ECBBrowser.Browser.EvaluateScriptAsync(script, new TimeSpan(0, 0, 1));
response.ContinueWith(t =>
{
count--;
if (count == 0) this.initializeMap();
});
_loadedLayers.Add(layer);
}
else
{
count--;
if(count == 0) this.initializeMap();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
Update II
I now believe something has changed with the resource loading.
This is what I have (unimportant parts are left out).
public class ECBSchemeHandler : IResourceHandler
{
private string _mimeType;
private Stream _stream;
public bool Open(IRequest request, out bool handleRequest, ICallback callback)
{
var result = open(request, callback);
handleRequest = result;
return result;
}
public bool Read(Stream dataOut, out int bytesRead, IResourceReadCallback callback)
{
return read(dataOut, out bytesRead, callback);
}
public bool ReadResponse(Stream dataOut, out int bytesRead, ICallback callback)
{
return read(dataOut, out bytesRead, callback);
}
private bool open(IRequest request, ICallback callback)
{
var u = new Uri(request.Url);
var file = u.Authority + u.AbsolutePath;
var ass = Assembly.GetExecutingAssembly();
var resourcePath = ECBConfiguration.DEFAULT_ASSEMBLY_NAMESPACE + "." + file.Replace("/", ".");
if (ass.GetManifestResourceInfo(resourcePath) != null)
{
Task.Run(() =>
{
using (callback)
{
_stream = ass.GetManifestResourceStream(resourcePath);
var fileExtension = Path.GetExtension(file);
_mimeType = ResourceHandler.GetMimeType(fileExtension);
callback.Continue();
}
});
return true;
}
else
{
callback.Dispose();
}
return false;
}
private bool read(Stream dataOut, out int bytesRead, IDisposable callback)
{
callback.Dispose();
if (_stream == null)
{
bytesRead = 0;
return false;
}
//Data out represents an underlying buffer (typically 32kb in size).
var buffer = new byte[dataOut.Length];
bytesRead = _stream.Read(buffer, 0, buffer.Length);
dataOut.Write(buffer, 0, buffer.Length);
return bytesRead > 0;
}
}
}
Using the built-in ResourceHandlers as pointed out by #amaitland solved the problem with the Javascript registration.
I'm trying to make a signal based system for my Javascript application and i have something similar to this:
class EventHubListener {
constructor(eventName, callback, errorHandling) {
this.eventName = eventName;
this.callback = callback;
this.errorHandling = errorHandling;
}
}
class EventsHub {
constructor() {
this.listeners = [];
this.idgen = 0;
this.defaultErrorHandler = null;
}
registerListener(listenerInstance) {// EventHubListener
this.listeners.push(listenerInstance);
return listenerInstance.id = ++idgen;
}
register(eventName, callback, errorHandling) {
return registerListener(new EventHubListener(eventName, callback, errorHandling));
}
watchRemoteChange(type, field, callback, handling) {
return register('EvtRemoteStateChange', (data)=> {
if(!data || data.ObjectType !== type || !data.ChangedObject)
return;
callback(data.changedObject.id, data.ChangedObject[field]);
}, handling);
}
unregisterListener(id) {
this.listeners = this.listeners.filter(i=> i.id != id);
}
raise(eventName, data) {
this.listeners.forEach(l=> l.eventName === eventName, listener=> {
try {
if(listener.eventName === eventName)
listener.callback(data);
} catch(err) {
if(listener.errorHandling) {
try {
listener.errorHandling(err);
} catch(internalError) {
this.handleError(internalError);
}
} else {
this.handleError(err);
}
}
});
}
handleError(err) {
if(this.defaultErrorHandler) {
try {
this.defaultErrorHandler(err);
} catch(errorHandlingError) {
console.trace('Error in the default error handling routine', err, errorHandlingError);
}
} else {
throw internalError;
}
}
}
// use
hub.watchRemoteChange('Products', 'SellingPrice', (id, value)=> {
console.writeLine(`Product ${id} has changed price to ${value}!`);
});
My problem here is that I suppose that this "use" example will make the Hub class hold a reference to this annonymous function:
(id, value)=> {
console.writeLine(`Product ${id} has changed price to ${value}!`);
}
Which in this example doesn't seem a big problem, but it could be using values from the closure which would be eventually collected in case the user class is collected (I guess?), the thing I need here is a way to detect that the user class has been disposed and make the hub class stop holding them or their closures and possibly avoid executing broken closures, is there a way to do that in the library side or do I have to manually always manage unregistering my listeners from user code?
I have a simple SignalR proxy with a single client method on it. The javascript looks like the following:
var proxy = $.connection.orderStatusUpdateEmitter;
proxy.client.onOrderUpdated = function(order){
try {
//This is only hit sometimes
getCustomerOrders(userId)
} catch (e) {
}
}
proxy.connection.start().done(function(c){
$log.info('Connected to order status update emitter');
});
proxy.connection.disconnected = function(data){
$log.info('disconnected');
setTimeout(function() {
proxy.connection.start();
},20000);
}
It seems like there is some type of race condition or I am doing this incorrectly because the handler for onOrderUpdated is not consistently hit. Anything glaringly wrong with the implementation above?
There is nothing special happening in my hub on the server, it looks like the following:
[AuthorizeClaims]
public class OrderStatusUpdateEmitter : Hub
{
private static string _groupIdentifier = "OrderStatusUpdate";
public override Task OnConnected()
{
var identity = Context.Request.Environment["user.identity"] as AuthenticatedUserIdentity;
Groups.Add(Context.ConnectionId, string.Format("{0}-{1}", _groupIdentifier, identity.UserId));
return base.OnConnected();
}
public override Task OnReconnected()
{
var identity = Context.Request.Environment["user.identity"] as AuthenticatedUserIdentity;
Groups.Add(Context.ConnectionId, string.Format("{0}-{1}", _groupIdentifier, identity.UserId));
return base.OnReconnected();
}
public static string GetGroupIdentifier()
{
return _groupIdentifier;
}
public Order OnOrderUpdate(Order order)
{
Clients.Group(String.Format("{0}-{1}",GetGroupIdentifier(),
order.CustomerId)).onOrderUpdated(obj);
}
}
Try the following instead of Group
list is consisting of users with ',' separator.
string[] group = list.Split(',');
for(int i=0; i < group.length; i++)
Clients.User(group[i]).onOrderUpdated(obj);
I want to call a method within a method for clientside but I don't know how to handle it, i've tried by calling like myFunction()and this.myFunction() but it is not working... This is my code
Template.decision.rendered = function () {
if ($(".active").length == 0) {
var random = Math.floor(Math.random() * 1000);
var $items = $(".item");
$items.eq(random % $items.length).addClass("active");
}
$.each($(".item"), function (index, value) {
if (Session.get($(this).attr('id'))) {
this.showResults(value.option);
}
});
};
Template.decision.showResults = function($option) {
$('#result').html('Option ' + $option + ' is voted');
};
As you can see I want to call showResults for each item inside rendered callback...
Found it using Template.decision.showResults(); silly me.
I think that a better way depending on what you are trying to do would be either to use a Session variable or a Meteor Method:
Session Variable.
Template.decision.created = function() {
Session.setDefault('showResults', false);
}
Template.decision.rendered = function() {
// [...]
$.each($(".item"), function (index, value) {
if (Session.get($(this).attr('id'))) {
Session.set('showResults', true);
}
});
}
Template.decision.showResults = function() {
return Session.get('showResults');
}
// in your template
<template name="decision">
{{#if showResults}}
<p>Here is the results.</p>
{{/if}}
</template>
Meteor Method.
// On the client.
Template.decision.rendered = function() {
// [...]
$.each($(".item"), function (index, value) {
if (Session.get($(this).attr('id'))) {
Meteor.call('showResults', function(error, result) {
if (!error and result === true) {
$('.class').hide() // It is here that you modify the DOM element according to the server response and your needs.
}
});
}
});
}
// Server-side method
// But, if you want it to react like a stub, put it inside your lib folder.
Meteor.methods({
showResults: function() {
// do your thing
result = true; // let's say everything works as expected on server-side, we return true
return result;
}
});
Here is how the code is.
function AppAssistant() {
this.dbObj = new DatabaseAssistant();
this.schemaObj = new SchemaAssistant();
this.result = {};
}
AppAssistant.prototype.setup = function() {
}
AppAssistant.prototype.handleLaunch = function(launchParams) {
if (gConfigDatabase.engine == "sqllite") {
} else {
}
}
AppAssistant.prototype.processResult = function() {
}
AppAssistant.prototype.execMigrations = function(version) {
}
// Database error handler
// If the db does not exists, it will generate set of tables
AppAssistant.prototype.errorHandler = function() {
Mojo.Log.info("In app asst error handler.");
if (gConfigDatabase.engine == "sqllite") {
try {
// execute some queries to create tables and insert some values in the HTML Opendatabase.
// Show disclaimer Page
Mojo.Controller.stageController.pushScene('disclaimer');
} catch (e) {
Mojo.Log.error("In AppAssistant errorHandler : ", e);
}
} else {
Mojo.Log.info("db8 part of app asst error handler");
try {
// execute operations to create kinds for db8 analogous to tables
Mojo.Controller.stageController.pushScene("disclaimer");
} catch (e) {
Mojo.Log.info("Error in db8 appAsst error handler", e);
}
}
}
AppAssistant.prototype.handleCommand = function(event) {
}
All this was done to support both sqllite and db8 for an webOS app. The problem i am facing is that when i configure a variable (gConfigDatabase) as sqllite then the Mojo.Controller.stageController.pushScene` method which is there in the errorHandler function works. but when i change it so that db8 engine is used, then i get an error saying undefined method pushScene. Any clues or hints on debugging or solving this ?