SignalR client disconnect/connect on every refresh of pages. ASP.NET MVC - asp.net-mvc

I am creating a chat embedded in my asp.net mvc 4 project. I have an online users ul list which add a user on OnConnected and remove it on OnDisconnected.
So, my app isn't a SinglePage app, which means that it refreshes on pages all the time.
I am encountering some difficulties to treat with this online users list on the client side, because signalr calls OnDisconnected and OnConnected on every page refresh.
While the other client is navigating normally in app, it keep being removed and added on every refresh of page.
How to avoid this behavior on client?
I am trying to do some like this, on client which are running the page with usersOnline list...
var timeout;
chat.client.login = function (chatUser) {
addUser(chatUser);
window.clearTimeout(timeout);
};
chat.client.logout = function (chatUser) {
timeout = setTimeout(function () { removeUser(chatUser.Id); }, 3000);
};
But I am suffering to deal with multi-users scenario... Because if more than one user executes the hub onDisconnected before the timeout runs, the second will override the instance of the first.

There is indeed no real way around this. A client will always disconnect when leaving a page, and connects to SignalR again when the next page is loaded.
The only way around this is to create a SPA, so SignalR doesn't need to be disconnected by navigating away.
Using the idea of SignalR hubs is to allow real-time actions with minimal programming or complications - the best way would be for SignalR to be pulling from a list of currently logged in users, not active connections, as that could have the same user multiple times.
Therefore, I suggest, instead of OnConnected and OnDisconnected, put it in your AccountController, in the LogIn and LogOut methods. For example:
public ActionResult LogIn()
{
//other stuff
var hub = GlobalHost.ConnectionManager.GetHubContext</*Hub Title*/>();
hub.client.chat.login()
}
public ActionResult LogOut()
{
// other stuff
var hub = GlobalHost.ConnectionManager.GetHubContext</*Hub Title*/>();
hub.client.chat.logout()
}

Related

.NET Core MVC/Azure AD - 302 Found when making an ajax request

I am using Azure AD along with asp.net core mvc. The following code is the same with a default MVC project generated with Work or School Accounts authentication.
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
Everything works just fine for the most time. The app is basically a notepad. A user logs in and adds notes/tasks. Everything after logging in is done using ajax requests. After some time the app stops working because there is a need for authentication again. Note that if I refresh the page everything is working again.
Am I doing this right? Am I missing something or this kind of use case is not supported.
Should I just create a javascript function that will auto refresh the page after some time?
Should I just create a javascript function that will auto refresh the page after some time?
You could try to create a hidden iframe in all the templates used by the Web App to make automatic calls to a MVC controller method that forces a call to renew the authentication data on a regular basis.
This is achieved very easily by configuring an automatic javascript process in the front-end executed in a loop on a regular basis of 45'. This value could be configured or extracted from a configuration file too. The only key condition is that it must be less than one hour.
Here is the simplified example code related to MVC Controller:
/* Action method, inside "Account" controller class, to force renewal of user authentication session */
public void ForceSignIn()
{
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" },
OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
And here is the simplified example HTML and javascript code employed to call silently in a hidden iframe to MVC Controller:
<iframe id="renewSession" hidden></iframe>
<script>
setInterval( function ()
{ #if (Request.IsAuthenticated) {
<text>
var renewUrl = "/Account/ForceSignIn";
var element = document.getElementById("renewSession");
element.src = renewUrl;
</text>
}
},
1000*60*45
);
</script>
For more details, you could refer to this article which get the similar situation with you.
I found a simple solution by accident. My goal was to hit a check endpoint every minute and If I get a 302 status code I would redirect the user to the authentication page.
public IActionResult Check()
{
return Ok(new { });
}
I left the developer tools open and noticed that every 30 mins I get a bigger response.
And this actually refreshes the cookie and as a result there is no need to redirect the user.
So to sum up someone needs to do this check every 40-50 minutes because the expiration is set to ~1 hour by default.

ASP .NET MVC websocket client to save data in DB

I am struggling to achieve the following:
I have created a Java websocket server which publishes data every 1 sec.
In ASP MVC projest I would like to receive the data and save them in database only so no JS involved here.
I am able to read the websocket data using console application method below :
using WebSocketSharp;
List<string> readoutList = new List<string>();
public void receiveMessage() {
using (var ws = new WebSocket("ws://localhost:4567/socket/"))
{
ws.OnMessage += (sender, e) =>
{
if (e.IsText)
{
readoutList.Add(e.Data.ToString());
Console.WriteLine(e.Data.ToString());
}
};
ws.Connect();
Console.ReadKey(true);
}
}`
How to create a service of this kind within the ASP MVC project? I need some direction here.
MVC is stateless so you have to request back to the server to initiate the request (such as from a form post) but within the MVC controller response, you can kick off the request to the server (as an example using a different technology). The problem is there isn't necessarily a 1 to 1 translation in MVC; initiating the request using client-side JavaSvcript would be the option here. Initiating these types of requests within MVC may cause issues with timeouts too that you have to be aware of.
OR, you can consider a scheduled windows program or a windows service that is installed, which can manage itself and initiate the request every so often. I think this is the better option.

How can I store and persist multiple remoting sessions in an MVC application?

Imagine a monitoring website that connects to 50 services via .net remoting and polls them to check they are working and find out what they're up to, and display it.
The page uses ajax to hit the backend and the backend then connects to each one.
Ideally, I don't want it to open a connection, do the request, close the connection, for 50 connections, on a 5 second interval (unless this is the best practice way?). So I'd like MVC to persist the connections.
I can make a ConnectionManager static singleton to handle this (not sure where?), opening and closing connections as required/idling.
You could even have a ConnectionManager handle the server status, so if multiple people load the status webpage, the results are cached.
But is there a better way, especially one that is scaleable? You could have multiple ConnectionManager classes in a webfarm scenario as they won't clash afaik (you can have multiple connections open).
ATM I am doing this in my ajax methods:
TcpChannel tcpChannel = new TcpChannel();
ChannelServices.RegisterChannel(tcpChannel, false);
Type requiredType = typeof(ICatServerMarshaller);
ICatServerMarshaller remoteObject = (ICatServerMarshaller)Activator.GetObject(requiredType,
"tcp://localhost:4567/CatServerMarshaller");
string catStatus;
try
{
catStatus = remoteObject.GetCatStatus().ToString();
}
catch (SocketException ex)
{
catStatus = "Offline";
}
finally
{
ChannelServices.UnregisterChannel(tcpChannel);
}
return Json(new { catStatus = catStatus});

How to make screen client updates whenever an event occurred (MVC)?

I'am new in MVC. I'am currently working to transform a desktop to a web application.
I need to make an update to the user view when an event of an object occurred. I have an object that observe a humidity sensor. Let say This object will trigger an event when the humidity above 70%. The code might be like this:
Private Sub Humidity_Alert(sender As Object) Handles objSensor.Alert
'Update user chart
End Sub
In desktop application, I just make an update to the view as usual in realtime, but I don't have any idea yet how to return this event to the client in MVC, without using javascript timer to make an ajax call to request if there is any alert. How to solve my problem?
I would suggest using ASP.NET SignalR library: signalr.net
You can use it for real-time updates from server to client.
ASP.NET SignalR is a new library for ASP.NET developers that makes it incredibly simple to add real-time web functionality to your applications. What is "real-time web" functionality? It's the ability to have your server-side code push content to the connected clients as it happens, in real-time.
Some pseudo-code example:
SignalR Hub:
public class HumidityHub : Hub
{
public void RefreshChart(string data)
{
Clients.All.refreshChart(data);
}
}
ClientCode:
var hub = $.connection.humidityHub;
hub.client.refreshChart= function (data) {
//refresh your chart
};
$.connection.hub.start();
ServerCode:
var hubContext = GlobalHost.ConnectionManager.GetHubContext<HumidityHub >();
hubContext.Clients.All.refreshChart(data);

EF - SaveChanges() saves 2 records

I've got a ASP.NET Web Application hosted in Azure. Interestingly, sometimes the application creates two records in database.
Could anyone please confirm whether I'm doing anything silly below?
Repository snippets:
private SomeEntity entities = new SomeEntity ();
public void Add(SomeObject _someObject)
{
entities.EmployeeTimeClocks.AddObject(_someObject);
}
public void Save()
{
entities.SaveChanges();
}
Create snippets:
repo.Add(someObject);
repo.Save();
Note: I'm using SQL Azure for persitent storage.
I've got this JQuery to show loading, this may be causing this issue?
$('#ClockInOutBtn').click(function () {
jQuery('#Loading').showLoading(
{
'afterShow': function () { setTimeout("$('form').submit();", 2000) }
}
);
});
The server-side code looks good.
I think this problem is most likely caused at the javascript/client layer - I'd guess that somehow you are getting two form submits occurring.
To debug this, try:
using Firebug (or IE or Chrome's debuggers) to detect the issue.
using fiddler to check what is sent over the network from client to server.
using Trace inside ASP.Net MVC to detect how many times your controller is being called.
If the problem turns out to be clientside, then you could fix this using some kind of check to prevent duplicate submissions - depending on your application's requirements, it might be worth adding this check on both client and server.

Resources