locked
ASP.NET MVC CHAT RRS feed

  • Question

  • User1201172537 posted

    I built an ajax chat in one of my mvc website. everything is working fine. I am using polling. At certain interval i am using $.post to get the messages from the db. But there is a problem. The message retrieved using $.post keeps on repeating. here is my javascript code and controller method.

    javascript method:

    var t;        
            function GetMessages() {        
                var LastMsgRec = $("#hdnLastMsgRec").val();
                var RoomId = $("#hdnRoomId").val();
                //Get all the messages associated with this roomId
                $.post("/Chat/GetMessages", { roomId: RoomId, lastRecMsg: LastMsgRec }, function(Data) {
                    if (Data.Messages.length != 0) {
                        $("#messagesCont").append(Data.Messages);
                        if (Data.newUser.length != 0)
                            $("#usersUl").append(Data.newUser);
                        $("#messagesCont").attr({ scrollTop: $("#messagesCont").attr("scrollHeight") - $('#messagesCont').height() });
                        $("#userListCont").attr({ scrollTop: $("#userListCont").attr("scrollHeight") - $('#userListCont').height() });
                    }
                    else {
                    }
                    $("#hdnLastMsgRec").val(Data.LastMsgRec);
                }, "json");
                
               
                t = setTimeout("GetMessages()", 3000);
            }


    Controller method:

    public JsonResult GetMessages(int roomId,DateTime lastRecMsg)
            {
                StringBuilder messagesSb = new StringBuilder();
                StringBuilder newUserSb = new StringBuilder();            
                List<Message> msgs = (dc.Messages).Where(m => m.RoomID == roomId && m.TimeStamp > lastRecMsg).ToList();
                if (msgs.Count == 0)
                {
                    return Json(new { Messages = "", LastMsgRec = System.DateTime.Now.ToString() });
                }            
                foreach (Message item in msgs)
                {
                    messagesSb.Append(string.Format(messageTemplate,item.User.Username,item.Text));
                    if (item.Text == "Just logged in!")
                        newUserSb.Append(string.Format(newUserTemplate,item.User.Username));
                }            
    
                return Json(new {Messages = messagesSb.ToString(),LastMsgRec = System.DateTime.Now.ToString(),newUser = newUserSb.ToString().Length == 0 ?"":newUserSb.ToString()});
            }

     

    Everything is working absloutely perfect. But i some messages getting repeated. The first time page loads i am retrieving the data and call GetMessages() function. I am loading the value of field hdnLastMsgRec the first time page loads and after the value for this field are set by the javascript.

    I think the message keeps on repeating because of asynchronous calls. I don't know, may be you guys can help me solve this.

    or you can suggest better way to implement this.

    Sunday, March 21, 2010 5:23 AM

Answers

  • User197322208 posted

    put this

    $("#hdnLastMsgRec").val(Data.LastMsgRec);

    immediately after

    function(Data) {

    and tell the results!

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, March 21, 2010 4:24 PM
  • User1314135081 posted

    I'm doing almost the same thing with my chat, keeping the last message id and requesting only what's above it. Sometimes I get a repetition but it appears only to the user who just sent a new message. The others don't see it and I'm guessing it's a js issue. However it doesn't appear very often so it's not a problem. I'm using jQuery templates to inject the json into html.

    In your case, does duplication appear only when you retrieve the messages?

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, March 21, 2010 4:35 PM
  • User-1032240251 posted

    Browsers will cache JSON just the same as they'll cache HTML, so make sure you're disabling browser caching in your JSON handlers.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, March 21, 2010 6:13 PM
  • User1201172537 posted

    thanks of the reply guys.

    i think the actual problem was with the timestamp thing and asynchronous behaviour of $.post.  after calling "GetMessages()" method, even if the previous request to retrive chat message was not complete anathor call to same method used to fire due to setting timeout for "GetMessages()" method outside the $.post method. In my question you can see that timeout for "GetMessages()" method is set outside the $.post method. Now i set the timeout for "GetMessages()" method inside the $.post method. so that next call to "GetMessages()" only occur after 3 seconds of completion of current $.post method. I have posted the code below.

     

     

    var t;
    function GetMessages() {
    var LastMsgRec = $("#hdnLastMsgRec").val();
    var RoomId = $("#hdnRoomId").val();
    //Get all the messages associated with this roomId
    $.post("/Chat/GetMessages", { roomId: RoomId, lastRecMsg: LastMsgRec }, function(Data) {
    if (Data.LastMsgRec.length != 0)
    $("#hdnLastMsgRec").val(Data.LastMsgRec);
    if (Data.Messages.length != 0) {
    $("#messagesCont").append(Data.Messages);
    if (Data.newUser.length != 0)
    $("#usersUl").append(Data.newUser);
    $("#messagesCont").attr({ scrollTop: $("#messagesCont").attr("scrollHeight") - $('#messagesCont').height() });
    $("#userListCont").attr({ scrollTop: $("#userListCont").attr("scrollHeight") - $('#userListCont').height() });
    }
    else {
    }
    t = setTimeout("GetMessages()", 3000);
    }, "json");

    }



     

    I addition to that i also changed few things. As suggested by ignatandrei   i placed  $("#hdnLastMsgRec").val(Data.LastMsgRec); immediately after function(Data) {.

    and also 

    as said by MikeSW i changed the data retrieval process. Previously i was extracting data on the basis of timespan(retrieve all the data associated with
    this room id that has greater timespan than last data retrieved message timespan) but now i keep track of the messageid. Now i retrieve only those data that
    has message id greater than last retrieved message id.


    and guess what no repeataion and perfectly working chat application so far on my intranet.

    I still got to see it's performance when deployed on internet.

    i think it solved my problem.

    i will still test the system and let u guys know if there is any problem.




     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, March 22, 2010 3:49 AM
  • User1314135081 posted

    The chat I've talked about is functional over internet (part of the game from my sig) and it works quite well (aside that seldom duplication message when you send it). I'm also caching the last 50 mesages or so in memory so retrieval is very fast. You can see it in action at  @XemerysDen (twitter) since the chat can be followed on twitter as well :) 

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, March 22, 2010 3:57 AM
  • User1314135081 posted

    I have a  chat "server" object which stays static and handles the mesages. Very simplistic and does the job.


    public class ChatServer:IChatServer
    	{
    		private IChatStorage _storage;
    		List<IChatMessage> _list;
    		
    		
    		public ChatServer(IChatStorage repo)
    		{
    			_storage = repo;
    		}
    
    		private object Sync
    		{
    			get
    			{
    				return ((IList) List).SyncRoot;
    			}
    		}
    
    		public void Add(int user, string message)
    		{
    			if (string.IsNullOrEmpty(message.Trim())) return;
    			if (message.Length > 250) message = message.Substring(0, 250);
    			var msg = new ChatMessage(user, message);
    			_storage.SaveMessage(msg);
    			lock(Sync)
    			{
    				_list.Add(msg);
    				if (_list.Count >= 75)
    				{
    					_list.RemoveRange(0, 25);
    				}
    			}
    			return;
    
    		}
    
    		List<IChatMessage> List
    		{
    			get
    			{
    				if (_list==null)
    				{
    					_list= new List<IChatMessage>(1);
    					_list.AddRange(_storage.GetLastMessages(50).OrderBy(d=>d.Id));
    				}
    				return _list;
    			}
    		}
    
    		public IEnumerable<IChatMessage> AllMessages
    		{
    			get 
    			{
    				return List;
    			}
    		}
    
    		public IEnumerable<IChatMessage> GetUpdates(int id)
    		{
    			return List.Where(d => d.Id > id).OrderByDescending(d=>d.Id);
    		}
    	}
    


    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, March 22, 2010 4:25 AM

All replies

  • User197322208 posted

    put this

    $("#hdnLastMsgRec").val(Data.LastMsgRec);

    immediately after

    function(Data) {

    and tell the results!

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, March 21, 2010 4:24 PM
  • User1314135081 posted

    I'm doing almost the same thing with my chat, keeping the last message id and requesting only what's above it. Sometimes I get a repetition but it appears only to the user who just sent a new message. The others don't see it and I'm guessing it's a js issue. However it doesn't appear very often so it's not a problem. I'm using jQuery templates to inject the json into html.

    In your case, does duplication appear only when you retrieve the messages?

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, March 21, 2010 4:35 PM
  • User-1032240251 posted

    Browsers will cache JSON just the same as they'll cache HTML, so make sure you're disabling browser caching in your JSON handlers.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, March 21, 2010 6:13 PM
  • User1201172537 posted

    thanks of the reply guys.

    i think the actual problem was with the timestamp thing and asynchronous behaviour of $.post.  after calling "GetMessages()" method, even if the previous request to retrive chat message was not complete anathor call to same method used to fire due to setting timeout for "GetMessages()" method outside the $.post method. In my question you can see that timeout for "GetMessages()" method is set outside the $.post method. Now i set the timeout for "GetMessages()" method inside the $.post method. so that next call to "GetMessages()" only occur after 3 seconds of completion of current $.post method. I have posted the code below.

     

     

    var t;
    function GetMessages() {
    var LastMsgRec = $("#hdnLastMsgRec").val();
    var RoomId = $("#hdnRoomId").val();
    //Get all the messages associated with this roomId
    $.post("/Chat/GetMessages", { roomId: RoomId, lastRecMsg: LastMsgRec }, function(Data) {
    if (Data.LastMsgRec.length != 0)
    $("#hdnLastMsgRec").val(Data.LastMsgRec);
    if (Data.Messages.length != 0) {
    $("#messagesCont").append(Data.Messages);
    if (Data.newUser.length != 0)
    $("#usersUl").append(Data.newUser);
    $("#messagesCont").attr({ scrollTop: $("#messagesCont").attr("scrollHeight") - $('#messagesCont').height() });
    $("#userListCont").attr({ scrollTop: $("#userListCont").attr("scrollHeight") - $('#userListCont').height() });
    }
    else {
    }
    t = setTimeout("GetMessages()", 3000);
    }, "json");

    }



     

    I addition to that i also changed few things. As suggested by ignatandrei   i placed  $("#hdnLastMsgRec").val(Data.LastMsgRec); immediately after function(Data) {.

    and also 

    as said by MikeSW i changed the data retrieval process. Previously i was extracting data on the basis of timespan(retrieve all the data associated with
    this room id that has greater timespan than last data retrieved message timespan) but now i keep track of the messageid. Now i retrieve only those data that
    has message id greater than last retrieved message id.


    and guess what no repeataion and perfectly working chat application so far on my intranet.

    I still got to see it's performance when deployed on internet.

    i think it solved my problem.

    i will still test the system and let u guys know if there is any problem.




     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, March 22, 2010 3:49 AM
  • User1314135081 posted

    The chat I've talked about is functional over internet (part of the game from my sig) and it works quite well (aside that seldom duplication message when you send it). I'm also caching the last 50 mesages or so in memory so retrieval is very fast. You can see it in action at  @XemerysDen (twitter) since the chat can be followed on twitter as well :) 

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, March 22, 2010 3:57 AM
  • User1201172537 posted

    Hi,

    MikeSW

    I don't know much about the caching the data in memory and then retrieving the data from cache. Can you please explain

    bit so that i can also implement it in my chat application.


    Monday, March 22, 2010 4:03 AM
  • User1314135081 posted

    I have a  chat "server" object which stays static and handles the mesages. Very simplistic and does the job.


    public class ChatServer:IChatServer
    	{
    		private IChatStorage _storage;
    		List<IChatMessage> _list;
    		
    		
    		public ChatServer(IChatStorage repo)
    		{
    			_storage = repo;
    		}
    
    		private object Sync
    		{
    			get
    			{
    				return ((IList) List).SyncRoot;
    			}
    		}
    
    		public void Add(int user, string message)
    		{
    			if (string.IsNullOrEmpty(message.Trim())) return;
    			if (message.Length > 250) message = message.Substring(0, 250);
    			var msg = new ChatMessage(user, message);
    			_storage.SaveMessage(msg);
    			lock(Sync)
    			{
    				_list.Add(msg);
    				if (_list.Count >= 75)
    				{
    					_list.RemoveRange(0, 25);
    				}
    			}
    			return;
    
    		}
    
    		List<IChatMessage> List
    		{
    			get
    			{
    				if (_list==null)
    				{
    					_list= new List<IChatMessage>(1);
    					_list.AddRange(_storage.GetLastMessages(50).OrderBy(d=>d.Id));
    				}
    				return _list;
    			}
    		}
    
    		public IEnumerable<IChatMessage> AllMessages
    		{
    			get 
    			{
    				return List;
    			}
    		}
    
    		public IEnumerable<IChatMessage> GetUpdates(int id)
    		{
    			return List.Where(d => d.Id > id).OrderByDescending(d=>d.Id);
    		}
    	}
    


    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, March 22, 2010 4:25 AM
  • User1201172537 posted

    thanks for the reply mike. I will try to implement it.


    Monday, March 22, 2010 4:35 AM