This project has moved. For the latest updates, please go here.

how to use with console app

Jan 4, 2010 at 9:33 PM

Hello,

First off I say this is one great piece of code! I am trying to run a server inside of a console app, but everytime I do try to create a server I get an exception in the constructor because the SynchronizationContextProperties listed are not all supported.

 

        public ServerTcpSocket()

        {

            SynchronizationContextRegister.Verify(SynchronizationContextProperties.NonReentrantPost | SynchronizationContextProperties.NonReentrantSend | SynchronizationContextProperties.Sequential | SynchronizationContextProperties.Synchronized);

        }

How to fix please?

 

 

Coordinator
Jan 4, 2010 at 11:34 PM

Excellent question!

The SynchronizationContextProperties register was added to detect and warn about situations exactly like this.

The Problem (brief description)

Asynchronous components need a "context" to send their events to (in a sense, the context owns the component). This context is normally a "main loop" of some kind. Console applications do not provide a context by default.

The Solution (quick version)

Use the Nito.Async.ActionThread to "own" the server socket. The socket's events will then be raised on that thread. ActionThread has some good example code.

Other solutions are possible, e.g., creating a main loop for the main console thread and having it "own" the socket. This is harder to implement, though; let me know if you want more details for this approach.

       -Steve

Mar 29, 2010 at 9:28 PM

Is it possible you can drop a quick sample on how Nito.Async.ActionThread to "own" the server socket? I encounter the same problem while trying to port your SimplerServer application to run as a Windows Service via Topshelf library.

I got the following exception at the creation of the class

_listeningSocket = new SimpleServerTcpSocket();

and it threw the following exception

"[InvalidOperationException] This asynchronous object cannot be used with this SynchronizationContext"

 

 

Mar 29, 2010 at 9:40 PM

I tried the following and it apparently work

 

       public void Start()
        {
            using (ActionThread actionThread = new ActionThread())
            {
                actionThread.Start();
                actionThread.Do(() =>
                    {
                        _communicationServer.StartListening(7750);
                    });
            }
            _logger.Info("Start the socket server");
        }

 

 

       public void Start()
        {
            using (ActionThread actionThread = new ActionThread())
            {
                actionThread.Start();

                actionThread.Do(() =>
                    {
                        _communicationServer.StartListening(7750);
                    });
            }

            _logger.Info("Start the socket server");

        }

 

 

 

 

Mar 29, 2010 at 9:44 PM

With above code, the server listens to the port without exception. However, when I have a client trying to connect, I receive the following exception

 

 

class ActionThreadWithBackgroundWorker
System.ObjectDisposedException was unhandled
  Message=Safe handle has been closed
  Source=mscorlib
  ObjectName=""
  StackTrace:
       at Microsoft.Win32.Win32Native.SetEvent(SafeWaitHandle handle)
       at System.Threading.EventWaitHandle.Set()
       at Nito.Async.ActionDispatcher.QueueAction(Action action)
       at Nito.Async.ActionDispatcherSynchronizationContext.Post(SendOrPostCallback d, Object state)
       at System.ComponentModel.AsyncOperation.Post(SendOrPostCallback d, Object arg)
       at System.ComponentModel.AsyncOperation.PostOperationCompleted(SendOrPostCallback d, Object arg)
       at Nito.Async.Sync.<>c__DisplayClass1e.<SynchronizeAsyncCallback>b__1c(IAsyncResult asyncResult)
       at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
       at System.Net.ContextAwareResult.CompleteCallback(Object state)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Net.ContextAwareResult.Complete(IntPtr userToken)
       at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
       at System.Net.Sockets.Socket.AcceptCallback(Object nullState)
       at System.Net.Sockets.Socket.RegisteredWaitCallback(Object state, Boolean timedOut)
       at System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(Object state, Boolean timedOut)
  InnerException: 

class ActionThreadWithBackgroundWorker

 

System.ObjectDisposedException was unhandled

  Message=Safe handle has been closed

  Source=mscorlib

  ObjectName=""

  StackTrace:

       at Microsoft.Win32.Win32Native.SetEvent(SafeWaitHandle handle)

       at System.Threading.EventWaitHandle.Set()

       at Nito.Async.ActionDispatcher.QueueAction(Action action)

       at Nito.Async.ActionDispatcherSynchronizationContext.Post(SendOrPostCallback d, Object state)

       at System.ComponentModel.AsyncOperation.Post(SendOrPostCallback d, Object arg)

       at System.ComponentModel.AsyncOperation.PostOperationCompleted(SendOrPostCallback d, Object arg)

       at Nito.Async.Sync.<>c__DisplayClass1e.<SynchronizeAsyncCallback>b__1c(IAsyncResult asyncResult)

       at System.Net.LazyAsyncResult.Complete(IntPtr userToken)

       at System.Net.ContextAwareResult.CompleteCallback(Object state)

       at System.Threading.ExecutionContext.runTryCode(Object userData)

       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)

       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)

       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

       at System.Net.ContextAwareResult.Complete(IntPtr userToken)

       at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)

       at System.Net.Sockets.Socket.AcceptCallback(Object nullState)

       at System.Net.Sockets.Socket.RegisteredWaitCallback(Object state, Boolean timedOut)

       at System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(Object state, Boolean timedOut)

  InnerException: 

 

Coordinator
Mar 30, 2010 at 3:48 PM

The reason you're getting an ObjectDisposedException is because in your Start() method, you create an ActionThread and then dispose it.

Later, when the client connects, it attempts to inform the ActionThread of the connection, and causes the exception.

You need to keep a reference to the ActionThread in your service class. Start it in the OnStart and dispose (join) it in the OnStop.

There's a console example of using ActionThread in the documentation here:
     http://nitoasync.codeplex.com/SourceControl/changeset/view/28147#533821

The Windows Service code would be very similar.

        -Steve

Mar 30, 2010 at 4:07 PM

Got it. It works now. Thanks a lot.  I post this snippet for other people that might get into the same trouble. This piece of code works runs under Topshelf, which is a console/windows service framework (http://topshelf-project.com/)

 

 

 public class SocketServer
    {
        Logger _logger;
        CommunicationServer _communicationServer;

        ActionThread _actionThread;

        public SocketServer(Logger logger, CommunicationServer commServer)
        {
            _logger = logger;
            _communicationServer = commServer;
        }

        public void Start()
        {
            _actionThread = new ActionThread();
            _actionThread.Start();
            _actionThread.Do(() =>
                    {
                        _communicationServer.StartListening(7750);
                    });

            _logger.Info("Start socket server");

        }

        public void Stop()
        {
            _communicationServer.Stop();
            _actionThread.Join();
        }

        public void Paused() { }
        public void Continued() { }
    }