Client/Client.cs
author sl
Tue, 16 Dec 2014 13:24:12 +0100
changeset 78 f0dda362f77e
parent 77 042c1fa136b9
child 80 408ef0501cb7
permissions -rw-r--r--
Prevent stackoverflow when client reconnects.
Client now specifies layout rather than relying on default one.
sl@20
     1
using System;
sl@20
     2
using System.Collections.Generic;
sl@20
     3
using System.Linq;
sl@20
     4
using System.Text;
sl@20
     5
using System.Threading.Tasks;
sl@20
     6
using System.Windows.Forms;
sl@55
     7
using SharpDisplay;
sl@20
     8
using System.ServiceModel;
sl@20
     9
using System.ServiceModel.Channels;
sl@20
    10
sl@20
    11
sl@20
    12
namespace SharpDisplayClient
sl@20
    13
{
sl@25
    14
    /// <summary>
sl@25
    15
    ///
sl@25
    16
    /// </summary>
sl@31
    17
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
sl@55
    18
    public class Callback : ICallback, IDisposable
sl@20
    19
    {
sl@31
    20
        private MainForm MainForm { get; set; }
sl@31
    21
sl@31
    22
        public Callback(MainForm aMainForm)
sl@31
    23
        {
sl@31
    24
            MainForm = aMainForm;
sl@31
    25
        }
sl@31
    26
sl@20
    27
        public void OnConnected()
sl@20
    28
        {
sl@20
    29
            //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread);
sl@20
    30
            //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId);
sl@20
    31
sl@20
    32
            MessageBox.Show("OnConnected()", "Client");
sl@20
    33
        }
sl@20
    34
sl@20
    35
sl@32
    36
        public void OnCloseOrder()
sl@20
    37
        {
sl@20
    38
            //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread);
sl@20
    39
            //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId);
sl@20
    40
sl@21
    41
            //MessageBox.Show("OnServerClosing()", "Client");
sl@31
    42
            MainForm.CloseConnectionThreadSafe();
sl@31
    43
            MainForm.CloseThreadSafe();
sl@20
    44
        }
sl@25
    45
sl@25
    46
        //From IDisposable
sl@25
    47
        public void Dispose()
sl@25
    48
        {
sl@25
    49
sl@25
    50
        }
sl@20
    51
    }
sl@20
    52
sl@20
    53
sl@25
    54
    /// <summary>
sl@25
    55
    ///
sl@25
    56
    /// </summary>
sl@31
    57
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
sl@55
    58
    public class Client : DuplexClientBase<IService>
sl@20
    59
    {
sl@30
    60
        public string SessionId { get { return InnerChannel.SessionId; } }
sl@26
    61
sl@57
    62
        public Client(ICallback aCallback)
sl@57
    63
            : base(new InstanceContext(aCallback), new NetTcpBinding(SecurityMode.None, true), new EndpointAddress("net.tcp://localhost:8001/DisplayService"))
sl@20
    64
        { }
sl@20
    65
sl@32
    66
        public void SetName(string aClientName)
sl@20
    67
        {
sl@32
    68
            Channel.SetName(aClientName);
sl@26
    69
        }
sl@26
    70
sl@62
    71
        public void SetLayout(TableLayout aLayout)
sl@62
    72
        {
sl@62
    73
            Channel.SetLayout(aLayout);
sl@62
    74
        }
sl@62
    75
sl@74
    76
        public void SetField(DataField aField)
sl@20
    77
        {
sl@74
    78
            Channel.SetField(aField);
sl@20
    79
        }
sl@20
    80
sl@74
    81
        public void SetFields(System.Collections.Generic.IList<DataField> aFields)
sl@20
    82
        {
sl@74
    83
            Channel.SetFields(aFields);
sl@67
    84
        }
sl@67
    85
sl@32
    86
        public int ClientCount()
sl@32
    87
        {
sl@32
    88
            return Channel.ClientCount();
sl@32
    89
        }
sl@57
    90
sl@57
    91
        public bool IsReady()
sl@57
    92
        {
sl@74
    93
            return State == CommunicationState.Opened || State == CommunicationState.Created;
sl@57
    94
        }
sl@20
    95
    }
sl@73
    96
sl@73
    97
sl@73
    98
    /// <summary>
sl@78
    99
    /// Handle connection with our Sharp Display Server.
sl@78
   100
    /// If the connection is faulted it will attempt to restart it.
sl@73
   101
    /// </summary>
sl@73
   102
    public class DisplayClient
sl@73
   103
    {
sl@78
   104
        private Client iClient;
sl@78
   105
        private Callback iCallback;
sl@78
   106
        private bool resetingConnection = false;
sl@78
   107
sl@73
   108
        private MainForm MainForm { get; set; }
sl@73
   109
        public string SessionId { get { return iClient.SessionId; } }
sl@74
   110
        public string Name { get; private set; }
sl@74
   111
        private TableLayout Layout { get; set; }
sl@74
   112
        private System.Collections.Generic.IList<DataField> Fields { get; set; }
sl@74
   113
sl@73
   114
sl@73
   115
        public DisplayClient(MainForm aMainForm)
sl@73
   116
        {
sl@73
   117
            MainForm = aMainForm;
sl@73
   118
            Name = "";
sl@74
   119
            Fields = new DataField[]{};
sl@73
   120
        }
sl@73
   121
sl@78
   122
        /// <summary>
sl@78
   123
        /// Initialize our server connection.
sl@78
   124
        /// </summary>
sl@73
   125
        public void Open()
sl@73
   126
        {
sl@73
   127
            iCallback = new Callback(MainForm);
sl@73
   128
            iClient = new Client(iCallback);
sl@73
   129
        }
sl@73
   130
sl@78
   131
        /// <summary>
sl@78
   132
        /// Terminate our server connection.
sl@78
   133
        /// </summary>
sl@73
   134
        public void Close()
sl@73
   135
        {
sl@73
   136
            iClient.Close();
sl@73
   137
            iClient = null;
sl@73
   138
            iCallback.Dispose();
sl@73
   139
            iCallback = null;
sl@73
   140
        }
sl@73
   141
sl@78
   142
        /// <summary>
sl@78
   143
        /// Tells whether a server connection is available.
sl@78
   144
        /// </summary>
sl@78
   145
        /// <returns>True if a server connection is available. False otherwise.</returns>
sl@73
   146
        public bool IsReady()
sl@73
   147
        {
sl@73
   148
            return (iClient != null && iCallback != null && iClient.IsReady());
sl@73
   149
        }
sl@73
   150
sl@78
   151
        /// <summary>
sl@78
   152
        /// Check if our server connection is available and attempt reset it if it isn't.
sl@78
   153
        /// This is notably dealing with timed out connections.
sl@78
   154
        /// </summary>
sl@73
   155
        public void CheckConnection()
sl@73
   156
        {
sl@78
   157
            if (!IsReady() && !resetingConnection)
sl@73
   158
            {
sl@74
   159
                //Try to reconnect
sl@73
   160
                Open();
sl@74
   161
sl@78
   162
                //Avoid stack overflow in case of persisting failure
sl@78
   163
                resetingConnection = true;
sl@78
   164
sl@78
   165
                try
sl@74
   166
                {
sl@78
   167
                    //On reconnect there is a bunch of properties we need to reset
sl@78
   168
                    if (Name != "")
sl@78
   169
                    {
sl@78
   170
                        iClient.SetName(Name);
sl@78
   171
                    }
sl@78
   172
sl@78
   173
                    SetLayout(Layout);
sl@78
   174
                    SetFields(Fields);
sl@74
   175
                }
sl@78
   176
                finally
sl@78
   177
                {
sl@78
   178
                    //Make sure our this state does not get out of sync
sl@78
   179
                    resetingConnection = true;
sl@78
   180
                }
sl@73
   181
            }
sl@73
   182
        }
sl@73
   183
sl@73
   184
        public void SetName(string aClientName)
sl@73
   185
        {
sl@73
   186
            Name = aClientName;
sl@73
   187
            CheckConnection();
sl@73
   188
            iClient.SetName(aClientName);
sl@73
   189
        }
sl@73
   190
sl@73
   191
sl@73
   192
        public void SetLayout(TableLayout aLayout)
sl@73
   193
        {
sl@74
   194
            Layout = aLayout;
sl@73
   195
            CheckConnection();
sl@73
   196
            iClient.SetLayout(aLayout);
sl@73
   197
        }
sl@73
   198
sl@74
   199
sl@74
   200
        public void SetField(DataField aField)
sl@73
   201
        {
sl@74
   202
            //TODO: Create fields if not present
sl@74
   203
            int i = 0;
sl@74
   204
            foreach (DataField field in Fields)
sl@74
   205
            {
sl@74
   206
                if (field.Index == aField.Index)
sl@74
   207
                {
sl@74
   208
                    //Update our field then
sl@74
   209
                    Fields[i] = aField;
sl@74
   210
                    break;
sl@74
   211
                }
sl@74
   212
                i++;
sl@74
   213
            }
sl@74
   214
sl@73
   215
            CheckConnection();
sl@74
   216
            iClient.SetField(aField);
sl@73
   217
        }
sl@73
   218
sl@74
   219
        public void SetFields(System.Collections.Generic.IList<DataField> aFields)
sl@73
   220
        {
sl@74
   221
            Fields = aFields;
sl@73
   222
            CheckConnection();
sl@74
   223
            iClient.SetFields(aFields);
sl@73
   224
        }
sl@73
   225
sl@73
   226
sl@73
   227
        public int ClientCount()
sl@73
   228
        {
sl@73
   229
            CheckConnection();
sl@73
   230
            return iClient.ClientCount();
sl@73
   231
        }
sl@73
   232
sl@73
   233
sl@73
   234
sl@73
   235
    }
sl@73
   236
sl@73
   237
sl@20
   238
}