In my chat application project, I am trying to broadcast usernames to all the users whenever a new user is connected to a server. and remove a username whenever the user leaves the server. The below is the code which I have tried by going through tutorials. (please check the file.js file which is not showing the desired output)
Chat.cs (Working) --> Implements "Hub" class of SignalR
public class Chat : Hub
{
/* showing only related content */
static ConcurrentDictionary<string, User> _users = new ConcurrentDictionary<string, User>();
public override Task OnDisconnected()
{
var user = _users[Context.ConnectionId]; //user as ConnectionId
User removedUser; //new class object
_users.TryRemove(Context.ConnectionId, out removedUser);
return Clients.All.leave(user, DateTime.Now.ToString()); //dynamic expression
}
public void Joined()
{
User user = new User(Context.ConnectionId, Clients.Caller.username);
_users.TryAdd(user.ConnectionID, user);
Clients.All.joins(user.ConnectionID, user.Name, DateTime.Now); //dynamic expression
}
}
User.cs (Working)
public class User
{
public User(string ConnID, string Username)
{
Name = Username;
ConnectionID = ConnID;
}
public string Name { get; set; }
public string ConnectionID { get; set; }
}
file.js (not working)
var chatUsername = window.prompt("Enter Username:", ""); //username
var chat = $.connection.chat; //connection
//
chat.client.joins = function (ConnectionId, name, Date) {
ConnectionId = 1; /* given value to just test */
name = chatUsername;
};
chat.client.leave = function (user, date) {
user = ""; //making the string empty so that the disconnected user value will be lost.
};
//Here is the connection which calls the "Joined" function of the server (Chat.cs)
What should I write in file.js functions (joins and leave) so that I will get the desired result as I mentioned above. Before asking here, I have gone through this site which is doing the same but including additional javascript files(knockout.js and json) which I dont want to include.(bcos I am new to jquery).
In order to pass UserNames to the client you can take your dictionary and in your joined server side method you could change the SignalR line to be:
Clients.All.joins(_users.Values); //dynamic expression
Then the client version of joins would be:
chat.client.joins = function (users) {
for(var i = users.length - 1; i >= 0; i--) {
alert("User Name: " + users[i].Name + "\nUser Connection ID: " + users[i].ConnectionID);
}
};
Of course you can handle the user information differently than alerting it, but that's the gist of how to handle the data. Lastly, I'd recommend against passing down the connection ID to everyone because a third party could then easily hijack it.
Related
I have some belows , please help me how i can get Session in Javascript code from Controller ?
public ActionResult Login(FormCollection f)
{
string sAcount = f["txtAccount"].ToString();
string sPassword = f.Get("txtPassword").ToString();
tblCustom cs = db.tblCustoms.SingleOrDefault(n=>n.Account==sAccount && n.Password==sPassword);
if (cs != null)
{
Session["Account"] = cs;
return View();
}
return View();
}
and JS code is
<script >
$('#btnSendMsg').click(function () {
var msg = $("#txtMessage").val();
alert('Hello' + Session["Account"] );
});
<script/>
the result is alert stil is not working, help me.
You should not update sessions many times, the type of data stored in Sessions are User Roles, Page Permissions and other global information. Once the login is done you should set login cookie. For login, you should use FormsAuthentication cookie.
Follow set Forms authentication to set forms authentication cookie.
Or check this link Create Forms Authentication cookie.
In the page use
alert("#HttpContext.Current.User.Identity.Name");
Although this doesn't directly answer your question, the preferred approach is to create ViewModels while passing and retrieving parameters.
Create a LoginViewModel:
public class LoginViewModel {
public tblCustoms Customs { get; set; }
//other stuff you have, you might consider moving account and password here too,
//instead of capturing with textbox names
//public string Account { get; set; }
//public string Password { get; set }
}
Pass that instead to the view.
public ActionResult Login(FormCollection f)
{
string sAcount = f["txtAccount"].ToString();
string sPassword = f.Get("txtPassword").ToString();
var cs = db.tblCustoms.SingleOrDefault(n=>n.Account==sAccount && n.Password==sPassword);
if (cs != null)
{
Session["Account"] = cs;
//return View(); you don't need this line
}
return View(new LoginViewModel() { Customs = cs });
}
Add to top of your view:
#model YourNameSpace.LoginViewModel
And in the javascript:
<script>
$('#btnSendMsg').click(function () {
var msg = $("#txtMessage").val();
alert('Hello ' + #Model.Customs );
});
<script/>
As an alternative to all of these, you can use ViewBag.
In the controller method, assign it to any name:
ViewBag.Customs = cs;
Then call it in the view:
alert('Hello ' + #ViewBag.Customs );
In order to use Session in your view, try this:
#Session["Account"].ToString();
My scenario is there are two different users login with same user id and password.mean time one of the person change the password by giving the current password. And changed the password at same time the another user gives current password what he logged in was incorrect. So i wants to add logout from all other devices in my web application.how can i do that
There is of course more than one approach, my first idea would be to hook the sessions to the ServletContext. Something like
// this can be in some util class, let's call it SessionUtil
static final String SESSION_REGISTER = "session.register";
public static synchronized void registerSession(ServletRequest req, HttpSession ses, String userName) {
ServletContext ctx = req.getServletContext();
Map<String, List<HttpSession>> register = (Map<String, List<HttpSession>>) ctx.getAttribute(SESSION_REGISTER);
if (register == null) {
register = new HashMap<>();
ctx.setAttribute(SESSION_REGISTER, register);
}
List<HttpSession> sessions = register.computeIfAbsent(userName, k -> new ArrayList<>());
sessions.add(ses);
}
Then, in your code, you need to register the user's session after login:
HttpSession ss = request.getSession();
if (isUser(name,password)) {
ss.setAttribute("user",name)
SessionUtil.registerSession(request, ss, name);
}
Finally, you need a method (again in SessionUtil class) to invalidate all the user's sessions (except the current one):
public static synchronized void invalidateSessions(ServletRequest req, HttpSession current, String userName) {
ServletContext ctx = req.getServletContext();
Map<String, List<HttpSession>> register = (Map<String, List<HttpSession>>) ctx.getAttribute(SESSION_REGISTER);
if (register != null) {
List<HttpSession> sessions = register.get(userName);
if (sessions != null) {
for (HttpSession ses : sessions) {
if (!ses.equals(current)) {
ses.invalidate();
}
}
}
}
}
Then you can call this method e.g. when the user changes his/her password.
Note #1: Not a very nice code, it misses some sanity checks and synchronized can be smaller chunks of code. It's just to give you an idea.
Note #2: The functionality of the registerSession(...) method can be done using the HttpSessionAttributeListener, but I've never used it yet, so cannot give an example.
I am working on a Javascript multiplayer game and I need to send a Javascript object from one client to another client using signalR. Till now I am sending client to client data by string or array.
But I don't know how to receive Javascript object in server for sending that object to another client.
var MyInfo = {
UserName: loginUserName,
userid: logInUserId,
getinfo: function() {
return this.UserName + ' ' + this.userid;
}
}
Which data type shall I use to receive that Javascript data in my hub.
I am working on C# .NET MVC.
I got the answer of my problem...
C# language provides automatically conversion of Javascript object to Object data type. Thus I send the Javascript object to server and then receive that object in Object datatype. After that I send that object to destination client, as follow:
var MyInfo = {
UserName: loginUserName,
userid: logInUserId,
getinfo: function() {
return this.UserName + ' ' + this.userid;
}
};
var MyInfo2 = {
UserName: "",
userid: "",
getinfo: function() {
return this.UserName + ' ' + this.userid;
}
};
var chessR = $.connection.gameHub;
var myConnectionID;
chessR.client.testObject = function(temp) {
MyInfo2.UserName = temp.UserName;
MyInfo2.userid = temp.userid;
alert(MyInfo2.getinfo());
}
$.connection.hub.start().done(function() {
chessR.server.testObject(MyInfo);
});
On signalR hub I write:
public class GameHub : Hub
{
public void testObject(Object MyInfo)
{
Clients.Caller.testObject(MyInfo);
}
}
Now the problem solved.
I think the easy way to go would be creating a MyInfoModel on the server side containing the same properties of the JS model and simply pass it on the server method.
Normally, SignalR and ASP.NET should handle the serialization of your data, letting you to send and recieve complex objects. (Please note that I have not tested it, it is just an educated guess). Since you can easily send complex objects from the server to the client, I see no reason why you cannot send them from the client to the server.
If the first approach (creating the model on the server and make the server method accept a model) doesn't work, you can serialize the object, send it as a string and deserialize it on the hub (you still need the model to deserialize).
If neither of these work, leave a message and when I get to a computer with VS I will test them and share the results.
Hope this helps! Good luck!
Your solution is good for sending the object between JS clients, but if you want to use the object on the C# base Server or get some typing (usually ideal), then you can create a C# model that matches the JS object.
And depending on the signalr Json serialize casing options you use, you can use attributes to specify how the C# object should be de/serialized:
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
public class MyInfoModel
{
[Required]
[JsonPropertyName("userId")]
public string UserId { get; set; }
[Required]
[JsonPropertyName("userName")]
public string UserName { get; set; }
}
JS client side (in typescript)
type UserInfo = {
userName: string;
userId: string;
};
const myInfo: UserInfo = {
userName: loginUserName,
userId: logInUserId,
};
await $.hubConnection.send("HubMethodWithTypedParam", myInfo);
Now the hub method can be declared with a typed parameter like this:
public class GameHub : Hub
{
public void HubMethodWithTypedParam(MyInfoModel myInfo)
{
...
}
}
I tried using presence to make it display the total connected users in an element. I can't really figure out how to make it work.
I also tried doing the following:
var dataUlist = new Firebase('https://<url>.firebaseio.com/.info/connected');
dataUlist.on('value', function(snap) {
console.log(snap);
});
To tried to see if I could find anything useful in there, but I couldn't figure out how the data works.
Is there any way to accomplice what I am after? Fetch the total number of connected users and then echo it out in the console or to an element?
.info/connected will only return information about whether the current client is connected or not. In order to maintain a presence count, you'll need to create a counter by storing presence information for each user and utilizing setOnDisconnect(). For example:
var listRef = new Firebase("https://<url>.firebaseio.com/presence/");
var userRef = listRef.push();
// Add ourselves to presence list when online.
var presenceRef = new Firebase("https://<url>.firebaseio.com/.info/connected");
presenceRef.on("value", function(snap) {
if (snap.val()) {
// Remove ourselves when we disconnect.
userRef.onDisconnect().remove();
userRef.set(true);
}
});
// Number of online users is the number of objects in the presence list.
listRef.on("value", function(snap) {
console.log("# of online users = " + snap.numChildren());
});
Here is the the code from Anant formatted for Android
public void getDbCount() {
Firebase listRef = new Firebase("https://<your-firebase-database>.firebaseio.com/presence/");
final Firebase userRef = listRef.push();
// Add ourselves to presence list when online.
Firebase presenceRef = new Firebase("https://<your-firebase-database>.firebaseio.com/.info/connected");
ValueEventListener myPresence = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
// Remove ourselves when we disconnect.
userRef.onDisconnect().removeValue();
userRef.setValue(true);
}
#Override
public void onCancelled(FirebaseError firebaseError) {
Log.e("DBCount", "The read failed: " + firebaseError.getMessage());
}
};
presenceRef.addValueEventListener(myPresence);
// Number of online users is the number of objects in the presence list.
ValueEventListener myList = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
// Remove ourselves when we disconnect.
Log.i("DBCount", "# of online users = " + String.valueOf(snapshot.getChildrenCount()));
}
#Override
public void onCancelled(FirebaseError firebaseError) {
Log.e("DBCount", "The read failed: " + firebaseError.getMessage());
}
};
listRef.addValueEventListener(myList);
}
I am quite new to SignalR.
My first assignment is to make simple chat app.
I have been browsing and reading and finally made a page where you come and chat and it works fine.
Now I need to show a list of connected clients. To achieve this I have wrote the following code.
This is my HUB.
public class ChatHub: Hub
{
chatEntities dc = new chatEntities();
public void Send(string message,string clientName)
{
Clients.addMessage(message,clientName);
}
// I want to save the user into my database, when they join
public void Joined(string userId,string userName)
{
CurrentChattingUsers cu = new CurrentChattingUsers();
cu.ConnectionId = userId;
cu.UserName = userName;
dc.CurrentChattingUsers.AddObject(cu);
dc.SaveChanges();
Clients.joins(userId, userName);
}
// This will return a list of connected user from my db table.
public List<ClientModel> GetConnectedUsers()
{
var query = (from k in dc.CurrentChattingUsers
select new ClientModel()
{
FullName = k.UserName,
UserId = k.ConnectionId
}).ToList();
return query;
}
}
And thats it...Now what??
Am I going to the right direction? If, I am then how to call this methods from the view?
Some good suggestions will really help me out.
cheers
EDIT:
I have added the following script when the hub start
$.connection.hub.start(function () {
chat.getConnectedUsers();
});
This is the method that returns the client names in my Hub
public List<ClientModel> GetConnectedUsers()
{
var data = (from k in dc.Users
select new ClientModel()
{
FullName = k.UserName
}).ToList();
Clients.loadUsers(data);
return data;
}
in firebug i can see it returns something as follows;
{"State":{},"Result":[{"FullName":"mokarom","UserId":null}, {"FullName":"aka8000","UserId":null},{"FullName":"johnnyno5","UserId":null},{"FullName":"reza","UserId":null},{"FullName":"amyo","UserId":null},{"FullName":"rezatech","UserId":null}],"Id":"0","Error":null,"StackTrace":null}
But, how would I display that in my view??
EDIT:
this the complete view so far
<script type="text/javascript">
var chat;
var myClientName
$(document).ready(function(){
myClientName = '#Request.Cookies["ChatterName"].Value';
// Created proxy
chat = $.connection.chatHub;
// Assign a function to be called by the server
chat.addMessage = onAddMessage;
// Register a function with the button click
$("#broadcast").click(onBroadcast);
$('#message').keydown(function (e) {
if (e.which == 13) { //Enter
e.preventDefault();
onBroadcast();
}
});
// Start the connection
$.connection.hub.start(function () {
chat.getConnectedUsers();
});
chat.loadUsers = function (data) {
loadUsers(data);
};
});
function onAddMessage(message,clientName) {
// Add the message to the list
$('#messages').append('<div class="chatterName">' + clientName + ' </div><div class="chatterMessage"> ' + message + '</div><div class="clear">');
}
function onBroadcast() {
// Call the chat method on the server
chat.send($('#message').val(), myClientName);
$('#message').val('');
}
function loadUsers(data) {
$('#clientList').html(data.Result[0].FullName);
}
</script>
Problem: don't see anything here: $('#clientList').html(data.Result[0].FullName);
firebug says 'data is not defined'
JavaScript
var chats = $.connection.chatHub;
chats.loadUsers = function (data) { loadUsers(data); };
var connectedUserCount = 0;
$.connection.hub.start(function ()
{ chats.getConnectedUsers(); });
function loadUsers = = function (data) {
console.log(data); //so you can see your data in firebug.etc
//which signal r will have converted to json so you could try
var numberOfUsers = data.length;
}
Once hub is started chats would have all the public functions of your hub available as javascript functions. This is what the signalr/hubs creates using the best available connection method between client and server.
In reverse your C# hub will have access to any javascripts functions you setup, e.g.
Clients.loadUsers(query);
//add this to you server side just before you return query
ps - you might also consider using OnConnectedAsync, though of course you might still persist these. I'm also waiting for full support for web farm support using sql, which is in the pipeline.