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