ExecuteJsonCommand AppServer.GetAllSessions() returns no sessions

Mar 6, 2012 at 8:29 PM
Edited Mar 6, 2012 at 8:34 PM

Hi

!!! Thanks in advance !!!

Basically I am attempting to use the JSON sub command to process my messages in an online virtual rooms type of app.  I can send/receive messages from my Jscript client but am having difficulty storing session data.

I am having what looks like a race condition in JOIN_ROOM::ExecuteJsonCommand.  It seems as if session.AppServer.GetAllSessions() is empty when this gets called and has no sessions.  But if i but a breakpoint inside the method at a line of code just "before" the "foreach(var s in session.AppServer.GetAllSessions()" loop sessions are returned by GetAllSessions() and the foreach loop executes as intended.

I obviously have set my server up wrong somehow - but for the life of me I cannot see where I have messed up??

** Please note that the reason I have subclassed WebSocketServer & WebSocketSession is because I could not for the life of me see a simple way of saying only send messages to sessions that I want using the JSON command pattern (seems simple enough when using the web application example).  In the basic JSON chat example i saw no way to store session data?  If someone can show me a better way of handling this - then please could you put me on the right path!!!!

For example :: this is basically what I was/am trying to achieve .

  public class WebSocketSession2 : WebSocketSession<T>
{
string
RoomId ; // store my additional data inside the session
}

Public
class JOIN_ROOM : JsonSubCommand<WebSocketSession2, WebRoom> { protected override void ExecuteJsonCommand(WebSocketSession2 session, WebRoom commandInfo) { // new client has joined the room - broadcast the fact to all the others string joinedRoom = GetJsonResponse(session, "JOINED_ROOM", new { Sender = commandInfo.Sender }); string room_occupationcount_update = GetJsonResponse(session, "ROOM_OCCUPANTCOUNT_UPDATE", new { Count = session.AppServer.SessionCount }); // logic to join room 'n' goes here .. // notify each session that user "Sender" has joined the room foreach(var s in session.AppServer.GetAllSessions()) {
if( s.RoomId != "22" ) continue; // only send to sessions attatched to room 22 for example

  s.SendResponseAsync(joinedRoom); // inform all clients that "Sender" has joined we dont need to wait for reply s.SendResponseAsync(room_occupationcount_update); // inform all clients that the room count has changed we dont need to wait for reply } } }

 

Can somebody please help me ?

Web.Config is at the bottom so you can see how i tie things in..

In severCommands.cs (part of my website code not a seperate assembly) i have the following code

APOLOGIES FOR THE AMOUNT OF CODE... :)

 
namespace SuperWebSocketWeb.Commands
{
  #region WebRoom
  public class WebRoom
  {
    public string Sender { get; set; }
    public string RoomID { get; set; }
  }

  public class CREATE_ROOM : JsonSubCommand<WebSocketSession2, WebRoom>
  {
    protected override void ExecuteJsonCommand(WebSocketSession2 session, WebRoom commandInfo)
    {
// Just store the sender "bob", "bill" etc here in **this** session !
  session.Username = commandInfo.Sender; } } #endregion #region JoinRoom public class JOIN_ROOM : JsonSubCommand<WebSocketSession2, WebRoom> { protected override void ExecuteJsonCommand(WebSocketSession2 session, WebRoom commandInfo) { // new client has joined the room - broadcast the fact to all the others string joinedRoom = GetJsonResponse(session, "JOINED_ROOM", new { Sender = commandInfo.Sender }); string room_occupationcount_update = GetJsonResponse(session, "ROOM_OCCUPANTCOUNT_UPDATE", new { Count = session.AppServer.SessionCount }); // logic to join room 'n' goes here .. // notify each session that user "Sender" has joined the room foreach(var s in session.AppServer.GetAllSessions()) {
********* I need to only send to those sessions that I choose...

********* I SHOULD HAVE AT LEAST ONE SESSION HERE BUT 9 times out of 10 this loop is not entered
********* Why dont I have at least one session by the time this method is executed ... (after all I am technically in a session)?????

  s.SendResponseAsync(joinedRoom); // inform all clients that "Sender" has joined we dont need to wait for reply s.SendResponseAsync(room_occupationcount_update); // inform all clients that the room count has changed we dont need to wait for reply } } } #endregion }

 

 

In global.asax I have the following WebSocketSession2 class; this is pretty boiler plate aside from subclassing WebSocketSession as WebSocketSession2 and WebSocketServer as WebSocketServer2

namespace SuperWebSocketWeb
{
public
class WebSocketSession2 : WebSocketSession<WebSocketSession2> { // in my custom session i just want a Username storing for now :) public string Username { get; set; } protected override void OnHandShaked() { string username = Cookies["username"]; // this does nothing as i never actually set it (not sure how to use this model) Username = username; } } public class WebSocketServer2 : WebSocketServer<WebSocketSession2> { public WebSocketServer2(ISubProtocol<WebSocketSession2> subProtocol) : base(subProtocol) { } public WebSocketServer2() : base() { } }
// boiler plate code from the web example code
public class Global : System.Web.HttpApplication { private List<WebSocketSession2> m_Sessions = new List<WebSocketSession2>(); private List<WebSocketSession2> m_SecureSessions = new List<WebSocketSession2>(); private object m_SessionSyncRoot = new object(); private object m_SecureSessionSyncRoot = new object(); void Application_Start(object sender, EventArgs e) { LogUtil.Setup(); StartSuperWebSocketByConfig(); }   void StartSuperWebSocketByConfig() { var serverConfig = ConfigurationManager.GetSection("socketServer") as SocketServiceConfig; if(!SocketServerManager.Initialize(serverConfig)) return; var socketServer = SocketServerManager.GetServerByName("SuperWebSocket") as WebSocketServer2; var secureSocketServer = SocketServerManager.GetServerByName("SecureSuperWebSocket") as WebSocketServer2; Application["WebSocketPort"] = socketServer.Config.Port; Application["SecureWebSocketPort"] = secureSocketServer.Config.Port; socketServer.NewSessionConnected += new SessionEventHandler<WebSocketSession2>(socketServer_NewSessionConnected); socketServer.SessionClosed += new SessionEventHandler<WebSocketSession2, CloseReason>(socketServer_SessionClosed); if(!SocketServerManager.Start()) SocketServerManager.Stop(); }   void socketServer_NewSessionConnected(WebSocketSession2 session) { lock(m_SessionSyncRoot) m_Sessions.Add(session); SendToAll("System: " + session.Cookies["username"] + " connected"); } void socketServer_SessionClosed(WebSocketSession2 session, CloseReason reason) { lock(m_SessionSyncRoot) m_Sessions.Remove(session); if(reason == CloseReason.ServerShutdown) return; if(session.Cookies != null) SendToAll("System: " + session.Cookies["username"] + " disconnected"); } void SendToAll(string message) { lock(m_SessionSyncRoot) { foreach(var s in m_Sessions) { s.SendResponseAsync(message); } } } void Application_End(object sender, EventArgs e) { SocketServerManager.Stop(); } }
}// namespace


And the web.config to tie it in...(note that i dont use a seperate assembly for the JSON sub protocol commands !!!

 <socketServer>
        <servers>
          <server name="SuperWebSocket"
                  serviceName="SuperWebSocket"
                  ip="Any" port="4502" mode="Async" >
            <subProtocols>
              <protocol>
                <commands>
                  <add assembly="SuperWebSocketWeb"/>
                </commands>
              </protocol>
            </subProtocols>


          </server>
            <server name="SecureSuperWebSocket"
                    serviceName="SuperWebSocket"
                    ip="Any" port="4503" mode="Sync" security="tls" >
                <!--Please install the certificate to your trusted certificates store, the password is 'supersocket'-->
                <certificate filePath="localhost.pfx"
                             password="supersocket"
                             isEnabled="true"></certificate>
            </server>


            <server name="FlashPolicyServer"
                      serviceName="FlashPolicyService"
                      ip="Any" port="843"
                      mode="Async"
                      receiveBufferSize="32"
                      maxConnectionNumber="100"
                      policyFile="crossdomain.xml"
                      clearIdleSession="true">
            </server>
          
            <server name="SilverlightPolicyServer"
                      serviceName="SilverlightPolicyService"
                      ip="Any" port="943"
                      mode="Async"
                      receiveBufferSize="32"
                      maxConnectionNumber="100"
                      policyFile="clientaccesspolicy.xml"
                      clearIdleSession="true">
            </server>
        </servers>
        <services>
          <service name="SuperWebSocket" type="SuperWebSocketWeb.WebSocketServer2, SuperWebSocketWeb" />
            <service name="SilverlightPolicyService"  type="SuperSocket.Facility.PolicyServer.SilverlightPolicyServer, SuperSocket.Facility" />
            <service name="FlashPolicyService"  type="SuperSocket.Facility.PolicyServer.FlashPolicyServer, SuperSocket.Facility" />
        </services>
    </socketServer>

 

 

WebSocketSession
Coordinator
Mar 7, 2012 at 12:50 AM
Could you take a look at the introduction of session snapshot setting of configuration on pages of SuperSocket? Another problem is foreach's threading issue.
Sent from my Windows Phone

From: PingCrosby
Sent: 3/7/2012 4:29 AM
To: kerry-jiang@hotmail.com
Subject: ExecuteJsonCommand AppServer.GetAllSessions() returns no sessions [SuperWebSocket:347553]

From: PingCrosby

Hi

!!! Thanks in advance !!!

Basically I am attempting to use the JSON sub command to process my messages in an online virtual rooms type of app. I can send/receive messages from my Jscript client but am having difficulty storing session data.

I am having what looks like a race condition in JOIN_ROOM::ExecuteJsonCommand. It seems as if session.AppServer.GetAllSessions() is empty when this gets called and has no sessions. But if i but a breakpoint inside the method "before" the foreach loop sessions are returned by GetAllSessions and the foreach loop executes as intended.

I obviously have set my server up wrong somehow - but for the life of me I cannot see where I have messed up??

** Please note that the reason I have subclassed WebSocketServer & WebSocketSession is because I could not for the life of me see a simple way of saying only send messages to sessions that I want using the JSON command pattern (seems simple enough when using the web application example). In the basic JSON chat example i saw no way to store session data? If someone can show me a better way of handling this - then please could you put me on the right path!!!!

For example :: this is basically what I was/am trying to achieve .

 public class JOIN_ROOM : JsonSubCommand<WebSocketSession2, WebRoom>
  {
    protected override void ExecuteJsonCommand(WebSocketSession2 session, WebRoom commandInfo)
    {
      // new client has joined the room - broadcast the fact to all the others
      string joinedRoom = GetJsonResponse(session, "JOINED_ROOM", new { Sender = commandInfo.Sender });
      string room_occupationcount_update = GetJsonResponse(session, "ROOM_OCCUPANTCOUNT_UPDATE", new { Count = session.AppServer.SessionCount });
  
      // logic to join room 'n' goes here ..

      // notify each session that user "Sender" has joined the room
      foreach(var s in session.AppServer.GetAllSessions())
      {
if( s.RoomId != "22" ) continue; // only send to sessions attatched to room 22 for example

s.SendResponseAsync(joinedRoom); // inform all clients that "Sender" has joined we dont need to wait for reply s.SendResponseAsync(room_occupationcount_update); // inform all clients that the room count has changed we dont need to wait for reply } } }

Can somebody please help me ?

Web.Config is at the bottom so you can see how i tie things in..

In severCommands.cs (part of my website code not a seperate assembly) i have the following code

APOLOGIES FOR THE AMOUNT OF CODE... :)

 
namespace SuperWebSocketWeb.Commands
{
  #region WebRoom
  public class WebRoom
  {
    public string Sender { get; set; }
    public string RoomID { get; set; }
  }

  public class CREATE_ROOM : JsonSubCommand<WebSocketSession2, WebRoom>
  {
    protected override void ExecuteJsonCommand(WebSocketSession2 session, WebRoom commandInfo)
    {
// Just store the sender "bob", "bill" etc here in **this** session !
session.Username = commandInfo.Sender; } } #endregion #region JoinRoom public class JOIN_ROOM : JsonSubCommand<WebSocketSession2, WebRoom> { protected override void ExecuteJsonCommand(WebSocketSession2 session, WebRoom commandInfo) { // new client has joined the room - broadcast the fact to all the others string joinedRoom = GetJsonResponse(session, "JOINED_ROOM", new { Sender = commandInfo.Sender }); string room_occupationcount_update = GetJsonResponse(session, "ROOM_OCCUPANTCOUNT_UPDATE", new { Count = session.AppServer.SessionCount }); // logic to join room 'n' goes here .. // notify each session that user "Sender" has joined the room foreach(var s in session.AppServer.GetAllSessions()) {
********* I need to only send to those sessions that I choose...

********* I SHOULD HAVE AT LEAST ONE SESSION HERE BUT 9 times out of 10 this loop is not entered
********* Why dont I have at least one session by the time this method is executed ... (after all I am technically in a session)?????

s.SendResponseAsync(joinedRoom); // inform all clients that "Sender" has joined we dont need to wait for reply s.SendResponseAsync(room_occupationcount_update); // inform all clients that the room count has changed we dont need to wait for reply } } } #endregion }

In global.asax I have the following WebSocketSession2 class

namespace SuperWebSocketWeb
{
public
class WebSocketSession2 : WebSocketSession<WebSocketSession2> { // in my custom session i just want a Username storing for now :) public string Username { get; set; } protected override void OnHandShaked() { string username = Cookies["username"]; // this does nothing as i never actually set it (not sure how to use this model) Username = username; } } public class WebSocketServer2 : WebSocketServer<WebSocketSession2> { public WebSocketServer2(ISubProtocol<WebSocketSession2> subProtocol) : base(subProtocol) { } public WebSocketServer2() : base() { } }
// boiler plate code from the web example code
public class Global : System.Web.HttpApplication { private List<WebSocketSession2> m_Sessions = new List<WebSocketSession2>(); private List<WebSocketSession2> m_SecureSessions = new List<WebSocketSession2>(); private object m_SessionSyncRoot = new object(); private object m_SecureSessionSyncRoot = new object(); void Application_Start(object sender, EventArgs e) { LogUtil.Setup(); StartSuperWebSocketByConfig(); } void StartSuperWebSocketByConfig() { var serverConfig = ConfigurationManager.GetSection("socketServer") as SocketServiceConfig; if(!SocketServerManager.Initialize(serverConfig)) return; var socketServer = SocketServerManager.GetServerByName("SuperWebSocket") as WebSocketServer2; var secureSocketServer = SocketServerManager.GetServerByName("SecureSuperWebSocket") as WebSocketServer2; Application["WebSocketPort"] = socketServer.Config.Port; Application["SecureWebSocketPort"] = secureSocketServer.Config.Port; socketServer.NewSessionConnected += new SessionEventHandler<WebSocketSession2>(socketServer_NewSessionConnected); socketServer.SessionClosed += new SessionEventHandler<WebSocketSession2, CloseReason>(socketServer_SessionClosed); if(!SocketServerManager.Start()) SocketServerManager.Stop(); } void socketServer_NewSessionConnected(WebSocketSession2 session) { lock(m_SessionSyncRoot) m_Sessions.Add(session); SendToAll("System: " + session.Cookies["username"] + " connected"); } void socketServer_SessionClosed(WebSocketSession2 session, CloseReason reason) { lock(m_SessionSyncRoot) m_Sessions.Remove(session); if(reason == CloseReason.ServerShutdown) return; if(session.Cookies != null) SendToAll("System: " + session.Cookies["username"] + " disconnected"); } void SendToAll(string message) { lock(m_SessionSyncRoot) { foreach(var s in m_Sessions) { s.SendResponseAsync(message); } } } void Application_End(object sender, EventArgs e) { SocketServerManager.Stop(); } }
}// namespace


And the web.config to tie it in...(note that i dont use a seperate assembly for the JSON sub protocol commands !!!

 <socketServer>
        <servers>
          <server name="SuperWebSocket"
                  serviceName="SuperWebSocket"
                  ip="Any" port="4502" mode="Async" >
            <subProtocols>
              <protocol>
                <commands>
                  <add assembly="SuperWebSocketWeb"/>
                </commands>
              </protocol>
            </subProtocols>


          </server>
            <server name="SecureSuperWebSocket"
                    serviceName="SuperWebSocket"
                    ip="Any" port="4503" mode="Sync" security="tls" >
                <!--Please install the certificate to your trusted certificates store, the password is 'supersocket'-->
                <certificate filePath="localhost.pfx"
                             password="supersocket"
                             isEnabled="true"></certificate>
            </server>


            <server name="FlashPolicyServer"
                      serviceName="FlashPolicyService"
                      ip="Any" port="843"
                      mode="Async"
                      receiveBufferSize="32"
                      maxConnectionNumber="100"
                      policyFile="crossdomain.xml"
                      clearIdleSession="true">
            </server>
          
            <server name="SilverlightPolicyServer"
                      serviceName="SilverlightPolicyService"
                      ip="Any" port="943"
                      mode="Async"
                      receiveBufferSize="32"
                      maxConnectionNumber="100"
                      policyFile="clientaccesspolicy.xml"
                      clearIdleSession="true">
            </server>
        </servers>
        <services>
          <service name="SuperWebSocket" type="SuperWebSocketWeb.WebSocketServer2, SuperWebSocketWeb" />
            <service name="SilverlightPolicyService"  type="SuperSocket.Facility.PolicyServer.SilverlightPolicyServer, SuperSocket.Facility" />
            <service name="FlashPolicyService"  type="SuperSocket.Facility.PolicyServer.FlashPolicyServer, SuperSocket.Facility" />
        </services>
    </socketServer>

WebSocketSession
Mar 7, 2012 at 12:30 PM

Hi

thanks for the reply - adding"disableSessionSnapshot=true" to my config seemed to sort it.  Still confused as to why when i am in the "ExecuteJsonCommand" i would not get the current session.

New web.config ...

<server name="SuperWebSocket" serviceName="SuperWebSocket" ip="Any" port="4502" mode="Async" disableSessionSnapshot="true" >

 


Coordinator
Mar 7, 2012 at 12:43 PM

Does the sample SuperWebSocketWeb work correctly for you?

Coordinator
Mar 7, 2012 at 1:39 PM

Does your server started up by configuration? If not, you need change programming config code.