locked
Pattern for Reading a Persistent StreamSocket

    Question

  • Greetings everyone. I am looking for the best way to implement the processing of events from a persistent socket connection. The application will have a persistent socket connection to a device. The communication is base on TCP and I am using a StreamSocket for this. The communication pattern is as follows:

    [MyApp] -- Query Status --> [Device]

                    <-- Response ---

    or

    [MyApp] <---- Event ---- [Device] (Something changed on the device)

    I have created a Model for the device that is bound to my View (a page). The model implements INotifyPropertyChanged so I expect the controls on the page to change when the properties of the model change.

    The problem I have is processing the InputStream because it is persistent and the Device is designed to work this way.

    I have looked at the examples such as:

    http://code.msdn.microsoft.com/windowsapps/Creating-a-ThreadPool-work-9665cdff

    The problem with this example is that it there is not concept of model and view. The worker thread is embedded in the view which would not be practical.

    [it would be nice if the StreamSocket or DataReader had an event similar to the StreamSocketListener Connection event so that I didn't need to mess around with background threads and marshalling etc]

    What I have done is in the model open a connection and start a worker thread to listen for events:

    public async Task Connect(MainPage MainPage)
            {
                _page = MainPage;
                HostName serverHostName = new HostName("xxx.xxx.x.x");
                string port = "60128";
                try
                {
                    if (_clientSocket != null)
                    {
                        _clientSocket.Dispose();
                    }
                    _clientSocket = new StreamSocket();
                    _clientSocket.Control.NoDelay = true;
    
                    //connect to the device
                    await _clientSocket.ConnectAsync(serverHostName, port);
    
                    //start the listener thread for reading data on the stream
                    await Task.Factory.StartNew(ReadDeviceEvents);
                }
                catch (Exception ex)
                {
                }
            }

    private async void ReadDeviceEvents()
            {
    
                if (_clientSocket != null)
                {
                    try
                    {
                        DataReader reader = new DataReader(_clientSocket.InputStream);
                        while (true)
                        {
                            string c = string.Empty;
                            //read the eISCP Header
                            uint sizeFieldCount = await reader.LoadAsync(16);
                            string sheader = reader.ReadString(16);
                            ISCPHeader header = new ISCPHeader(sheader);
                            //read the data
                            uint dataSize = await reader.LoadAsync(header.DataSize);
                            string data = reader.ReadString(dataSize);
                            ISCPResponse response = new ISCPResponse(header, data);
                            ProcessEvent(response);
                        }
                    }
                    catch (Exception ex)
                    {
    #if DEBUG
                        System.Diagnostics.Debug.WriteLine("ISCPController.ReadDeviceEvents() - Read Error: " + ex.Message);
    #endif
                    }
    
                }
            }

    private void ProcessEvent(ISCPResponse response)
            {
                System.Diagnostics.Debug.WriteLine(string.Format("Event Received CMD {0} PARM {1}", response.Command, response.Parameter));
                bool powerOn = false;
                if (response.Command.Equals("PWR"))
                {
                    if (response.Parameter.Equals("01"))
                    {
                        powerOn = true;
                    }
                    Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
                                        CoreDispatcherPriority.High,
                                        new DispatchedHandler(() =>
                                        {
                                            IsPowerOn = powerOn; //***** I was hoping this would trigger the bindings in the UI but it does not!
                                            _page.ProcessEvent(); /******* I don't want to have to do this. In my model I put a reference to the page to call this method on the page which set the DataContext to the Model again and refreshed the controls. There has to be a better way to do this.
    */
                                        }));
                }
            }

    Is there a better pattern I can implement to listen to the InputStream and process events which update my Model and up date the UI?

    Tuesday, June 10, 2014 6:06 PM

All replies

  • Sorry, I'm not a Model/View/MVVM expert. One thing I never understand is that when these frameworks get in your way, folks seem to spend a lot of time trying to make the flow fit the framework rather than getting the app to work. 

    In layman's terms, what are you trying to do?

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Wednesday, June 11, 2014 7:06 PM
    Moderator