signalr with sqldepdency firing multiple times for each browser instance - asp.net-mvc-4

I am having a asp.net mvc app with vs2013 and .net framwork 4.5.1 which should notify users when a certain field gets updated and for a certain recordID.
Everything works fine when I have a single instance of the browser open, but when i open another tab or browser either on the same machine or on the different machine it fires the sqldepdencychange event multiple times.
Below is my hub code
public class MessagesHub : Hub
{
private static string conString = ConfigurationManager.ConnectionStrings["FleetLink_DB"].ToString();
private static string hostName = "";
public static void SendMessages(string hName)
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MessagesHub>();
hostName = hName;
context.Clients.Group(hostName).updateMessages(hName);
}
public Task leaveGroup(string hName)
{
return Groups.Remove(Context.ConnectionId, hName);
}
public Task joinGroup(string hName)
{
return Groups.Add(Context.ConnectionId, hName);
}
}
Below is my signalr script file
$(function () {
var dialog, form
// Declare a proxy to reference the hub.
var notifications = $.connection.messagesHub;
//debugger;
//Create a function that the hub can call to broadcast messages.
notifications.client.updateMessages = function (hName) {
alert("testing");
getoneMessages(hName)
};
$.connection.hub.logging = true;
$.connection.hub.start().done(function () {
var hostName = getUrlVars()["System_Name"];
notifications.server.joinGroup(hostName);
}).fail(function (e) {
alert(e);
});
});
function getUrlVars() {
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for (var i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
function getoneMessages(hName) {
var tbl = $('#selectable');
//alert('mesgID=' + mesgID)
//var tbl = $('#selectable');
$.ajax({
url: '/controller/view',
cache: false,
contentType: 'application/html ; charset:utf-8',
type: 'GET',
dataType: 'html'
}).success(function (result) {
//alert(result);
tbl.empty().append(result);
}).error(function (exception) {
//alert('failed= ' + exception);
});
}
window.onbeforeunload = function (e) {
var hostName = getUrlVars()["System_Name"];
notifications.server.joinGroup(hostName);
$.connection.hub.stop();
};
Below is my partialview code along with the definition for RegisterForNotification and depdendency_onchange event
public PartialViewResult SignalRTesterPartialView()
{
/...COde not included for brevity..../
RegisterForNotifications(ID);
}
public void RegisterForNotifications(int mID)
{
var efConnectionString = ConfigurationManager.ConnectionStrings["DB"].ConnectionString;
var builder = new EntityConnectionStringBuilder(efConnectionString);
var regularConnectionString = builder.ProviderConnectionString;
string commandText = null;
commandText = "select ID,Status,Name from tblABC where ID=" + strID;
using (SqlConnection connection = new SqlConnection(regularConnectionString))
{
using (SqlCommand command = new SqlCommand(commandText, connection))
{
connection.Open();
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
// NOTE: You have to execute the command, or the notification will never fire.
var reader = command.ExecuteReader();
}
}
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change && e.Info== SqlNotificationInfo.Update)
{
MessagesHub.SendMessages(hName);
}
RegisterForNotifications(1012);
}
Not sure why it is firing the sendmessages multiple times with each additional browser instance that I open. Any pointers would be helpful!

remove EventHandler when you done with it
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change && e.Info== SqlNotificationInfo.Update)
{
MessagesHub.SendMessages(hName);
}
//remove event handler
SqlDependency dependency = sender as SqlDependency;
dependency.OnChange -= new OnChangeEventHandler(dependency_OnChange);
RegisterForNotifications(1012);
}

Related

Using MQTT ManagedClient with ASP NET API, how to?

I'm currently working on a project that has to rely heavily on MQTT - one of the parts that needs to utilize MQTT is a ASP Net API, but I'm having difficulties receiving messages.
Here is my MQTTHandler:
public MQTTHandler()
{
_mqttUrl = Properties.Resources.mqttURL ?? "";
_mqttPort = Properties.Resources.mqttPort ?? "";
_mqttUsername = Properties.Resources.mqttUsername ?? "";
_mqttPassword = Properties.Resources.mqttUsername ?? "";
_mqttFactory = new MqttFactory();
_tls = false;
}
public async Task<IManagedMqttClient> ConnectClientAsync()
{
var clientID = Guid.NewGuid().ToString();
var messageBuilder = new MqttClientOptionsBuilder()
.WithClientId(clientID)
.WithCredentials(_mqttUsername, _mqttPassword)
.WithTcpServer(_mqttUrl, Convert.ToInt32(_mqttPort));
var options = _tls ? messageBuilder.WithTls().Build() : messageBuilder.Build();
var managedOptions = new ManagedMqttClientOptionsBuilder()
.WithAutoReconnectDelay(TimeSpan.FromSeconds(5))
.WithClientOptions(options)
.Build();
_mqttClient = new MqttFactory().CreateManagedMqttClient();
await _mqttClient.StartAsync(managedOptions);
Console.WriteLine("Klient startet");
return _mqttClient;
}
public async Task PublishAsync(string topic, string payload, bool retainFlag = true, int qos = 1)
{
await _mqttClient.EnqueueAsync(new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload(payload)
.WithQualityOfServiceLevel((MQTTnet.Protocol.MqttQualityOfServiceLevel)qos)
.WithRetainFlag(retainFlag)
.Build());
Console.WriteLine("Besked published");
}
public async Task SubscribeAsync(string topic, int qos = 1)
{
var topicFilters = new List<MQTTnet.Packets.MqttTopicFilter>
{
new MqttTopicFilterBuilder()
.WithTopic(topic)
.WithQualityOfServiceLevel((MQTTnet.Protocol.MqttQualityOfServiceLevel)(qos))
.Build()
};
await _mqttClient.SubscribeAsync(topicFilters);
}
public Status GetSystemStatus(MqttApplicationMessageReceivedEventArgs e)
{
try
{
var json = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
var status = JsonSerializer.Deserialize<Status>(json);
if (status != null)
{
return status;
}
else
{
return null;
}
}
catch (Exception)
{
throw;
}
}
The above has been tested with a console app and works as it should.
The reason I need MQTT in the APi is that a POST method has to act on the value of a topic;
In particular I need to check a systems status before allowing the post;
[HttpPost]
public async Task<ActionResult<Order>> PostOrder(Order order)
{
if (_lastStatus != null)
{
if (_lastStatus.OpStatus)
{
return StatusCode(400, "System is busy!");
}
else
{
var response = await _orderManager.AddOrder(order);
return StatusCode(response.StatusCode, response.Message);
}
}
return StatusCode(400, "Something went wrong");
}
So I will need to set up a subscriber for this controller, and set the value of _lastStatus on received messages:
private readonly MQTTHandler _mqttHandler;
private IManagedMqttClient _mqttClient;
private Status _lastStatus;
public OrdersController(OrderManager orderManager)
{
_orderManager = orderManager;
_mqttHandler = new MQTTHandler();
_mqttClient = _mqttHandler.ConnectClientAsync().Result;
_mqttHandler.SubscribeAsync("JSON/Status");
_mqttClient.ApplicationMessageReceivedAsync += e =>
{
_lastStatus = _mqttHandler.GetSystemStatus(e);
return Task.CompletedTask;
};
}
However, it's behaving a little odd and I'm not experienced enough to know why.
The first time I make a POST request, _lastStatus is null - every following POST request seem to have the last retained message.
I'm guessing that I am struggling due to stuff being asynchronous, but not sure, and every attempt I've attempted to make it synchronous have failed.
Anyone have a clue about what I'm doing wrong?

error CS0103: The name 'ModelHelper' does not exist in the current context

I am trying to implement Object detection on HoloLens2 using Microsoft Custom Vision.
I have been following the tutorial (https://learn.microsoft.com/en-us/archive/blogs/appconsult/23535)
but faced with this error..
error CS0103: The name 'ModelHelper' does not exist in the current context
the codes are as below.
what is this ModelHelper for?
and is there anything that i have to add to use it?
using System;
using System.Linq;
using System.Threading.Tasks;
#if UNITY_WSA && !UNITY_EDITOR
using Windows.Media.Capture;
using Windows.Media.Capture.Frames;
using Windows.Media.MediaProperties;
public class ScanEngine
{
public TimeSpan PredictionFrequency = TimeSpan.FromMilliseconds(400);
private MediaCapture CameraCapture;
private MediaFrameReader CameraFrameReader;
private Int64 FramesCaptured;
IUnityScanScene UnityApp;
public ScanEngine()
{
}
public async Task Inititalize(IUnityScanScene unityApp)
{
UnityApp = unityApp;
await InitializeCameraCapture();
await InitializeCameraFrameReader();
}
private async Task InitializeCameraCapture()
{
CameraCapture = new MediaCapture();
MediaCaptureInitializationSettings settings = new
MediaCaptureInitializationSettings();
settings.StreamingCaptureMode = StreamingCaptureMode.Video;
await CameraCapture.InitializeAsync(settings);
}
private async Task InitializeCameraFrameReader()
{
var frameSourceGroups = await MediaFrameSourceGroup.FindAllAsync();
MediaFrameSourceGroup selectedGroup = null;
MediaFrameSourceInfo colorSourceInfo = null;
foreach (var sourceGroup in frameSourceGroups)
{
foreach (var sourceInfo in sourceGroup.SourceInfos)
{
if (sourceInfo.MediaStreamType == MediaStreamType.VideoPreview
&& sourceInfo.SourceKind == MediaFrameSourceKind.Color)
{
colorSourceInfo = sourceInfo;
break;
}
}
if (colorSourceInfo != null)
{
selectedGroup = sourceGroup;
break;
}
}
var colorFrameSource = CameraCapture.FrameSources[colorSourceInfo.Id];
var preferredFormat = colorFrameSource.SupportedFormats.Where(format =>
{
return format.Subtype == MediaEncodingSubtypes.Argb32;
}).FirstOrDefault();
CameraFrameReader = await CameraCapture.CreateFrameReaderAsync(colorFrameSource);
await CameraFrameReader.StartAsync();
}
public void StartPullCameraFrames()
{
Task.Run(async () =>
{
for (; ; ) // Forever = While the app runs
{
FramesCaptured++;
await Task.Delay(PredictionFrequency);
using (var frameReference = CameraFrameReader.TryAcquireLatestFrame())
using (var videoFrame = frameReference?.VideoMediaFrame?.GetVideoFrame())
{
if (videoFrame == null)
{
continue; //ignoring frame
}
if (videoFrame.Direct3DSurface == null)
{
videoFrame.Dispose();
continue; //ignoring frame
}
try
{
await
ModelHelper.EvaluateVideoFrameAsync(videoFrame).ConfigureAwait(false);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{
}
}
}
});
}
}
#endif

Azure Logic Apps internal server error 500

Am trying to create a an azure function that is triggered in a Logic Apps,
The functions purpose is to web crawl certain web sites, take the desired information, compare that with a a SQL Server database in Azure, compare if we already have that information if not add it.
My issue is that when ever i run it I get the Server 500 error, I assume its accessing the database that cause. Help?
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log
)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string RequestBody = await new StreamReader(req.Body).ReadToEndAsync();
{
return await CrawlBlog(0, RequestBody);
}
}
private static async Task<IActionResult> CrawlBlog(int Picker, string req)
{
int BlogPicker = Picker;
string TheResult = req;
//Get the url we want to test
var Url = "";
if (BlogPicker == 0)
{
Url = "*********";
}
else if (BlogPicker == 1)
{
Url = "*********";
}
/*
else if (BlogPicker == 2)
{
Url = "https://azure.microsoft.com/en-in/blog/?utm_source=devglan";
}
*/
else
{
TheResult = "False we got a wrong pick";
return (ActionResult)new OkObjectResult
( new {TheResult });
}
var httpClient = new HttpClient();
var html = await httpClient.GetStringAsync(Url);
var htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(html);
//a list to add all availabel blogs we found
var Blog = new List<BlogStats>();
switch (BlogPicker)
{
case 0:
{
var divs =
htmlDocument.DocumentNode.Descendants("div")
.Where(node => node.GetAttributeValue("class", "").Equals("home_blog_sec_text")).ToList();
foreach (var divo in divs)
{
var Blogo = new BlogStats
{
Summary = divo.Descendants("p").FirstOrDefault().InnerText,
Link = divo.Descendants("a").FirstOrDefault().ChildAttributes("href").FirstOrDefault().Value,
Title = divo.Descendants("a").FirstOrDefault().InnerText
};
Blog.Add(Blogo);
}
break;
}
case 1:
{
var divs =
htmlDocument.DocumentNode.Descendants("div")
.Where(node => node.GetAttributeValue("class", "").Equals("post_header_title two_third last")).ToList();
foreach (var divo in divs)
{
//string TheSummary = "we goofed";
var ThePs = divo.Descendants("p").ToList();
var Blogo = new BlogStats
{
Summary = ThePs[1].GetDirectInnerText(),
Link = divo.Descendants("a").LastOrDefault().ChildAttributes("href").FirstOrDefault().Value,
Title = divo.Descendants("a").FirstOrDefault().InnerText
};
Blog.Add(Blogo);
}
break;
}
}
TheResult = await SqlCheck(Blog[0].Title, Blog[0].Summary, Blog[0].Link); //error 500
return (ActionResult)new OkObjectResult
(
new
{
TheResult
}
);
}
public static async Task<string> SqlCheck(string Tit, string Sumy, string Lin)
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder.DataSource = "flygon.database.windows.net";
builder.UserID = "*****";
builder.Password = "********";
builder.InitialCatalog = "torkoal";
System.Data.DataSet ds = new System.Data.DataSet();
SqlConnection connection = new SqlConnection(builder.ConnectionString);
connection.Open();
SqlCommand CheckCommand = new SqlCommand("SELECT * FROM TableBoto WHERE Link = #id3 ", connection);
CheckCommand.Parameters.AddWithValue("#id3", Lin);
SqlDataAdapter dataAdapter = new SqlDataAdapter(CheckCommand);
dataAdapter.Fill(ds);
int i = ds.Tables[0].Rows.Count;
if (i > 0)
{
return $" We got a Duplicates in title : {Tit}";
}
try
{
{
string query = $"insert into TableBoto(Title,Summary,Link) values('{Tit}','{Sumy}','{Lin}');";
SqlCommand command = new SqlCommand(query, connection);
SqlDataReader reader = await command.ExecuteReaderAsync();
reader.Close();
}
}
catch (SqlException)
{
// Console.WriteLine(e.ToString());
}
connection.Close();
return $" Success Ign +{Tit} + Ign {Sumy}+ Ign {Lin} Ign Success SQL ";
}
}
500 HTTP status code is a generic code which means that the server was not able to process the request due to some issues, First step would be to add some exception handling to your function and see if the failure occurs and where it occurs.
On Side note, you should not use HTTP client in the way used in the code, you should not new it up every time your function executes, this client should be static in nature. Refer Manage connections in Azure Functions

Cannot send data if the connection is not in the 'Connected' State. - Multiple Hubs in SignalR

I'm attempting to get to grips with SignalR, to do so I'm trying to extend the functionality of the simple chat room tutorial that Microsoft provide in their documentation.
I'm now trying to add a second hub, which will allow the user to do send in integers and receive the value multiplied by 10. The hub itself is almost identical to the normal ChatHub, except with an extra step that checks the input is a number and does the multiplication.
ChatHub
public class ChatHub : Hub
{
public async Task SendMessage(string group,string user, string message)
{
await Clients.Group(group).SendAsync("ReceiveMessage", user, message);
}
public async Task AddToGroup(string groupName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} has joined the group {groupName}.");
}
}
CalcHub
public class CalcHub : Hub
{
public async Task SendMessage(string group, string user, string message)
{
var value = MultiplyByTen(message);
await Clients.Group(group).SendAsync("ReceiveMessage", user, value);
}
public async Task AddToGroup(string groupName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} has joined the group {groupName}.");
}
public string MultiplyByTen(string input)
{
bool isANumber = Int32.TryParse(input, out int value);
if (isANumber)
{
return (value * 10).ToString();
}
return "Not a number";
}
}
I have Javascript set up for my front-end, which works perfectly fine when I try to connect to the ChatHub and send messages, however when I attempt to use the connection to CalcHub, I get the Cannot send data if the connection is not in the 'Connected' State error message.
Here is how the two connections are established.
var calcConnection = new signalR.HubConnectionBuilder().withUrl("https://localhost:44309/calcHub").build();
var chatConnection = new signalR.HubConnectionBuilder().withUrl("https://localhost:44308/chatHub").build();
var activeConnection;
setConnection();
$("#hubSelector").on("change",
function(data) {
setConnection();
});
I have a simple select element that will swap the connection based on its value. SetConnection is the method that controls this, which is used at DOM ready to set the initial connection.
Both of the hubs are registered in my startup class too.
app.UseSignalR(routes =>
{
routes.MapHub<ChatHub>("/chatHub");
routes.MapHub<CalcHub>("/calcHub");
});
If I navigate to the two addresses of the hubs https://localhost:44309/calcHub and https://localhost:44309/chatHub, I can also see that they are valid addresses as I get the Connection ID required message.
Why is my calcHub not working?
Site.js
// Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification
// for details on configuring this project to bundle and minify static web assets.
// Write your JavaScript code.
$(function() {
var calcConnection = new signalR.HubConnectionBuilder().withUrl("https://localhost:44309/calcHub").build();
var chatConnection = new signalR.HubConnectionBuilder().withUrl("https://localhost:44308/chatHub").build();
var activeConnection;
//setConnection();
//$("#hubSelector").on("change",
// function(data) {
// setConnection();
// });
activeConnection.on("ReceiveMessage", function (user, message) {
var msg = message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
var encodedMsg = user + " says " + msg;
var li = document.createElement("li");
li.textContent = encodedMsg;
document.getElementById("messagesList").appendChild(li);
});
activeConnection.start().catch(function (err) {
return console.error(err.toString());
});
$("#addgroup").on("click", function () {
var group = document.getElementById("group").value;
activeConnection.invoke("AddToGroup", group).catch(function (err) {
return console.error(err.toString());
});
$("#group-list").append("<p>" + group + "</p>");
event.preventDefault();
});
$("#sendButton").on("click", function () {
var user = document.getElementById("userInput").value;
var message = document.getElementById("messageInput").value;
var group = document.getElementById("group").value;
activeConnection.invoke("SendMessage", group, user, message).catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
});
function setConnection() {
var selectValue = $("#hubSelector").val();
if (selectValue === "chat") {
$("#activeHub").html("<span>Active Hub: Chat</span>");
activeConnection = chatConnection;
}
if (selectValue === "calc") {
$("#activeHub").html("<span>Active Hub: Calc</span>");
activeConnection = calcConnection;
}
console.log(activeConnection);
}
});

Subscribe to DisplayAlert in Xamarin.Forms

I'd like to get notified whenever DisplayAlert is called somewhere in my app. The Xamarin.Forms source code suggests to use the MessagingCenter, since it is using it to send a message within DisplayAlert():
MessagingCenter.Send(this, AlertSignalName, args);
But I haven't been able to receive anything, yet. This is one of the lines I tried so far:
MessagingCenter.Subscribe<Page>(this, Page.AlertSignalName, arg => {
Console.WriteLine("Message received: " + arg);
});
Is this the right direction? Or do you have an alternative solution? I'd even consider some hacky reflection-based approach, since I need it for testing purposes only.
This works for me:
MessagingCenter.Subscribe<Page, Xamarin.Forms.Internals.AlertArguments>(this, Page.AlertSignalName, (obj, obj1) => {
int aa = 0;
});
But it is raised when DisplayAlert is displayed. (I think it's correct...)
This is my page:
using System;
using Xamarin.Forms;
namespace Test
{
public class MyPage : ContentPage
{
public MyPage()
{
Button b = new Button {Text = "Press" };
b.Clicked += async (object sender, EventArgs e) => {
await DisplayAlert("Attention", "AAA", "Ok");
MessagingCenter.Send<MyPage>(this, "AAA");
};
Content = new StackLayout
{
Children = {
new Label { Text = "Hello ContentPage" },
b
}
};
MessagingCenter.Subscribe<MyPage>(this, "AAA", (obj) => {
int aa = 0;
});
MessagingCenter.Subscribe<Page, Xamarin.Forms.Internals.AlertArguments>(this, Page.AlertSignalName, (obj, obj1) => {
int aa = 0;
});
}
}
}
In Xamarin source test code (namespace Xamarin.Forms.Core.UnitTests), it's used in a strongly typed way like that:
[Test]
public void DisplayAlert ()
{
var page = new ContentPage ();
AlertArguments args = null;
MessagingCenter.Subscribe (this, Page.AlertSignalName, (Page sender, AlertArguments e) => args = e);
var task = page.DisplayAlert ("Title", "Message", "Accept", "Cancel");
Assert.AreEqual ("Title", args.Title);
Assert.AreEqual ("Message", args.Message);
Assert.AreEqual ("Accept", args.Accept);
Assert.AreEqual ("Cancel", args.Cancel);
bool completed = false;
var continueTask = task.ContinueWith (t => completed = true);
args.SetResult (true);
continueTask.Wait ();
Assert.True (completed);
}
So this should do it:
MessagingCenter.Subscribe(this, Page.AlertSignalName, (Page sender, AlertArguments args) =>
{
Console.WriteLine("Message received: " + args.Message);
});