/// </summary> /// <exception cref="ConfigurationErrorsException"><see cref="SettingsCategory"/> has a value of null or empty string.</exception> public void LoadSettings() { if (m_persistSettings) { // Ensure that settings category is specified. if (string.IsNullOrEmpty(m_settingsCategory)) throw new ConfigurationErrorsException("SettingsCategory property has not been set"); // Load settings from the specified category. ConfigurationFile config = ConfigurationFile.Current; CategorizedSettingsElementCollection settings = config.Settings[m_settingsCategory]; settings.Add(nameof(Username), m_username, "Username to be used for authentication with the service.", false, SettingScope.User); settings.Add(nameof(Password), m_password, "Password to be used for authentication with the service.", true, SettingScope.User); settings.Add(nameof(SerializationFormat), m_serializationFormat, "Message serialization format for interactions with service, one of: Xml, Json or Binary. Default is Binary."); settings.Add(nameof(StatusMessageFilter), m_statusMessageFilter, "Command used to negotiate status message filter when client connects to the ServiceHelper."); Username = settings[nameof(Username)].ValueAs(m_username); Password = settings[nameof(Password)].ValueAs(m_password); SerializationFormat = settings[nameof(SerializationFormat)].ValueAs(m_serializationFormat); StatusMessageFilter = settings[nameof(StatusMessageFilter)].ValueAs(m_statusMessageFilter); } } /// <summary> /// Connects <see cref="RemotingClient"/> to <see cref="ServiceHelper.RemotingServer"/> and wait until authentication is complete. /// </summary> public void Connect() { if ((object)m_remotingClient == null) throw new InvalidOperationException("RemotingClient property of ClientHelper component is not set"); m_authenticationComplete = false; // Wait for connection. m_remotingClient.Connect(); while (!m_authenticationComplete && m_remotingClient.Enabled) { // Wait for authentication. Thread.Sleep(100); // If remoting client has been disposed (and set to null) while sleeping, go ahead and exit... if ((object)m_remotingClient == null) return; } if (m_remotingClient.Enabled) m_attemptReconnection = true; } /// <summary> /// Disconnects <see cref="RemotingClient"/> from <see cref="ServiceHelper.RemotingServer"/>. /// </summary> public void Disconnect() { m_attemptReconnection = false; if ((object)m_remotingClient != null) m_remotingClient.Disconnect(); } /// <summary> /// Sends a request to the <see cref="ServiceHelper"/> using <see cref="RemotingClient"/>. /// </summary> /// <param name="request">Request text to be sent.</param> public void SendRequest(string request) { ClientRequest requestInstance = ClientRequest.Parse(request); if ((object)requestInstance != null) SendRequest(requestInstance); else UpdateStatus(UpdateType.Warning, "Request command \"{0}\" is invalid\r\n\r\n", request); } /// <summary> /// Sends a request to the <see cref="ServiceHelper"/> using <see cref="RemotingClient"/>. /// </summary> /// <param name="request"><see cref="ClientRequest"/> object to be sent.</param> public void SendRequest(ClientRequest request) { try { // Intercept TRANSFER requests for uploads. if (request.Command == "TRANSFER" && request.Arguments.Exists("upload")) { string source = FilePath.GetAbsolutePath(request.Arguments["orderedarg1"]); if (File.Exists(source)) { // Attach the file content. request.Attachments.Add(File.ReadAllBytes(source)); } else { // File does not exist. throw new FileNotFoundException(string.Format("File '{0}' does not exist", source)); } } // Pass the request along. m_remotingClient.SendAsync(request); } catch (Exception ex) { UpdateStatus(UpdateType.Alarm, "Error processing request - {0}", ex.Message); } } /// <summary> /// Raises the <see cref="ReceivedServiceUpdate"/> event. /// </summary> /// <param name="type">One of the <see cref="UpdateType"/> values.</param> /// <param name="update">Update message received.</param> protected virtual void OnReceivedServiceUpdate(UpdateType type, string update) { if ((object)ReceivedServiceUpdate != null) ReceivedServiceUpdate(this, new EventArgs<UpdateType, string>(type, update)); } /// <summary> /// Raises the <see cref="ReceivedServiceResponse"/> event. /// </summary> /// <param name="response"><see cref="ServiceResponse"/> received.</param> protected virtual void OnReceivedServiceResponse(ServiceResponse response) { if ((object)ReceivedServiceResponse != null) ReceivedServiceResponse(this, new EventArgs<ServiceResponse>(response)); } /// <summary> /// Raises the <see cref="ServiceStateChanged"/> event. /// </summary> /// <param name="state">New <see cref="ServiceState"/>.</param> protected virtual void OnServiceStateChanged(ObjectState<ServiceState> state) { if ((object)ServiceStateChanged != null) ServiceStateChanged(this, new EventArgs<ObjectState<ServiceState>>(state)); } /// <summary> /// Raises the <see cref="ProcessStateChanged"/> event. /// </summary> /// <param name="state">New <see cref="ServiceProcessState"/>.</param> protected virtual void OnProcessStateChanged(ObjectState<ServiceProcessState> state) { if ((object)ProcessStateChanged != null) ProcessStateChanged(this, new EventArgs<ObjectState<ServiceProcessState>>(state)); } /// <summary> /// Raises the <see cref="AuthenticationSuccess"/> event. /// </summary> protected virtual void OnAuthenticationSuccess() { if ((object)AuthenticationSuccess != null) AuthenticationSuccess(this, EventArgs.Empty); m_authenticationComplete = true; } /// <summary> /// Raises the <see cref="AuthenticationFailure"/> event. /// </summary> protected virtual void OnAuthenticationFailure() { CancelEventArgs args = new CancelEventArgs(true); if ((object)AuthenticationFailure != null) AuthenticationFailure(this, args); // Continue connection attempts if requested. if (args.Cancel) { m_attemptReconnection = false; m_authenticationComplete = true; } } /// <summary> /// Raises the <see cref="TelnetSessionEstablished"/> event. /// </summary> protected virtual void OnTelnetSessionEstablished() { if ((object)TelnetSessionEstablished != null) TelnetSessionEstablished(this, EventArgs.Empty); } /// <summary> /// Raises the <see cref="TelnetSessionTerminated"/> event. /// </summary> protected virtual void OnTelnetSessionTerminated() { if ((object)TelnetSessionTerminated != null) TelnetSessionTerminated(this, EventArgs.Empty); } /// <summary> /// Releases the unmanaged resources used by the <see cref="ClientHelper"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { if (!m_disposed) { try { // This will be done regardless of whether the object is finalized or disposed. if (disposing) { // This will be done only when the object is disposed by calling Dispose(). Disconnect(); SaveSettings(); if ((object)m_remotingClient != null) { // Detach events from any existing instance m_remotingClient.ConnectionEstablished -= RemotingClient_ConnectionEstablished; m_remotingClient.ConnectionAttempt -= RemotingClient_ConnectionAttempt; m_remotingClient.ConnectionException -= RemotingClient_ConnectionException; m_remotingClient.ConnectionTerminated -= RemotingClient_ConnectionTerminated; m_remotingClient.ReceiveDataComplete -= RemotingClient_ReceiveDataComplete; } } } finally { m_disposed = true; // Prevent duplicate dispose. base.Dispose(disposing); // Call base class Dispose(). } } } private void UpdateStatus(UpdateType type, string message, params object[] args) { OnReceivedServiceUpdate(type, string.Format(message, args)); } private void RemotingClient_ConnectionAttempt(object sender, EventArgs e) { UpdateStatus(UpdateType.Information, "Connecting to {0}...\r\n\r\n", m_remotingClient.ServerUri); } private void RemotingClient_ConnectionEstablished(object sender, EventArgs e) { // Upon establishing connection with the service's communication client, we'll send our information to the // service so the service can keep track of all the client that are connected to its communication server. m_remotingClient.SendAsync(new ClientInfo(this)); StringBuilder status = new StringBuilder(); status.AppendFormat("Connected to {0}:", m_remotingClient.ServerUri); status.AppendLine(); status.AppendLine(); status.Append(m_remotingClient.Status); status.AppendLine(); UpdateStatus(UpdateType.Information, "{0}", status.ToString()); SendRequest(StatusMessageFilter); } private void RemotingClient_ConnectionException(object sender, EventArgs<Exception> e) { StringBuilder status = new StringBuilder(); TcpClient tcpClient; TlsClient tlsClient; status.AppendFormat("Exception during connection attempt: {0}", e.Argument.Message); status.AppendLine(); status.AppendLine(); UpdateStatus(UpdateType.Alarm, "{0}", status.ToString()); tlsClient = m_remotingClient as TlsClient; if ((object)tlsClient != null) { tlsClient.NetworkCredential = null; } else { tcpClient = m_remotingClient as TcpClient; if ((object)tcpClient != null) tcpClient.NetworkCredential = null; } } private void RemotingClient_ConnectionTerminated(object sender, EventArgs e) { StringBuilder status = new StringBuilder(); status.AppendFormat("Disconnected from {0}:", m_remotingClient.ServerUri); status.AppendLine(); status.AppendLine(); status.Append(m_remotingClient.Status); status.AppendLine(); UpdateStatus(UpdateType.Warning, "{0}", status.ToString()); // Attempt reconnection on a separate thread. if (m_attemptReconnection) { new Thread(state => { Thread.Sleep(1000); Connect(); }) .Start(); } } private void RemotingClient_ReceiveDataComplete(object sender, EventArgs<byte[], int> e) { ServiceResponse response; Serialization.TryDeserialize(e.Argument1.BlockCopy(0, e.Argument2), m_serializationFormat, out response); if ((object)response != null) { switch (response.Type) { case "UPDATECLIENTSTATUS-INFORMATION": UpdateStatus(UpdateType.Information, "{0}", response.Message); break; case "UPDATECLIENTSTATUS-WARNING": UpdateStatus(UpdateType.Warning, "{0}", response.Message); break; case "UPDATECLIENTSTATUS-ALARM": UpdateStatus(UpdateType.Alarm, "{0}", response.Message); break; case "AUTHENTICATIONSUCCESS": OnAuthenticationSuccess(); break; case "AUTHENTICATIONFAILURE": OnAuthenticationFailure(); break; case "SERVICESTATECHANGED": if (response.Attachments.Count > 0) { ObjectState<ServiceState> state = response.Attachments[0] as ObjectState<ServiceState>; if ((object)state != null) { // Notify change in service state by raising an event. OnServiceStateChanged(state); // Provide a status update for change in state of the service. UpdateType type = UpdateType.Information; switch (state.CurrentState) { case ServiceState.Stopped: case ServiceState.Paused: case ServiceState.Shutdown: type = UpdateType.Warning; break; } UpdateStatus(type, "State of service \"{0}\" has changed to \"{1}\".\r\n\r\n", state.ObjectName, state.CurrentState); } } break; case "PROCESSSTATECHANGED": if (response.Attachments.Count > 0) { ObjectState<ServiceProcessState> state = response.Attachments[0] as ObjectState<ServiceProcessState>; if ((object)state != null) { // Notify change in process state by raising an event. OnProcessStateChanged(state); // Provide a status update for change in state of the service process. UpdateType type = UpdateType.Information; switch (state.CurrentState) { case ServiceProcessState.Aborted: case ServiceProcessState.Exception: type = UpdateType.Alarm; break; } UpdateStatus(type, "State of process \"{0}\" has changed to \"{1}\".\r\n\r\n", state.ObjectName, state.CurrentState); } } break; case "TELNETSESSION": switch (response.Message.ToUpper()) { case "ESTABLISHED": OnTelnetSessionEstablished(); break; case "TERMINATED": OnTelnetSessionTerminated(); break; } break; case "TRANSFER:SUCCESS": if (response.Attachments.Count == 2) { // Extract data from response. byte[] content = (byte[])response.Attachments[0]; Arguments arguments = (Arguments)response.Attachments[1]; string target = arguments["orderedarg2"]; bool overwrite = arguments.Exists("overwrite"); target = FilePath.GetAbsolutePath(target); if (!File.Exists(target) || overwrite) { // Save the received file. UpdateStatus(UpdateType.Information, "Saving file '{0}'...\r\n\r\n", target); File.WriteAllBytes(target, content); UpdateStatus(UpdateType.Information, "File '{0}' saved successfully.\r\n\r\n", target); } else { // File exists and cannot be overwritten. UpdateStatus(UpdateType.Alarm, "File '{0}' already exists.\r\n\r\n", target); } } else { // Response is malformed. UpdateStatus(UpdateType.Alarm, "{0} response is malformed.\r\n\r\n", response.Type); } break; default: OnReceivedServiceResponse(response); break; } } } #endregion #region [ Static ] /// <summary> /// Returns an <see cref="ClientRequestInfo"/> object for the specified <paramref name="requestCommand"/> that can be used /// to invoke <see cref="ServiceHelper.ClientRequestHandlers"/> manually as if the request was sent by a <see cref="ClientHelper"/> remotely. /// </summary> /// <param name="requestCommand">Command for which an <see cref="ClientRequestInfo"/> object is to be created.</param> /// <returns>An <see cref="ClientRequestInfo"/> object.</returns> public static ClientRequestInfo PretendRequest(string requestCommand) { ClientRequest request = ClientRequest.Parse(requestCommand); ClientRequestInfo requestInfo = new ClientRequestInfo(new ClientInfo(), request); return requestInfo; } /// <summary> /// Attempts to parse an actionable response sent from the service. /// </summary> /// <param name="serviceResponse"><see cref="ServiceResponse"/> to test for actionable response.</param> /// <param name="sourceCommand">Command that invoked <paramref name="serviceResponse"/>.</param> /// <param name="responseSuccess">Boolean success state of <paramref name="serviceResponse"/>.</param> /// <returns><c>true</c> if actionable response was able to be parsed successfully; otherwise <c>false</c>.</returns> public static bool TryParseActionableResponse(ServiceResponse serviceResponse, out string sourceCommand, out bool responseSuccess) { bool parseSucceeded = false; sourceCommand = null; responseSuccess = false; try { string response = serviceResponse.Type; // Attempt to parse response message if (!string.IsNullOrWhiteSpace(response)) { // Response types are formatted as "Command:Success" or "Command:Failure" string[] parts = response.Split(':'); if (parts.Length > 1) { sourceCommand = parts[0].Trim().ToTitleCase(); responseSuccess = (string.Compare(parts[1].Trim(), "Success", StringComparison.OrdinalIgnoreCase) == 0); parseSucceeded = true; } } } catch { parseSucceeded = false; } return parseSucceeded; } #endregion }}Lines 501–990 of 990. Previous lines
/// </summary> /// <exception cref="ConfigurationErrorsException"><see cref="SettingsCategory"/> has a value of null or empty string.</exception> public void LoadSettings() { if (m_persistSettings) { // Ensure that settings category is specified. if (string.IsNullOrEmpty(m_settingsCategory)) throw new ConfigurationErrorsException("SettingsCategory property has not been set"); // Load settings from the specified category. ConfigurationFile config = ConfigurationFile.Current; CategorizedSettingsElementCollection settings = config.Settings[m_settingsCategory]; settings.Add(nameof(Username), m_username, "Username to be used for authentication with the service.", false, SettingScope.User); settings.Add(nameof(Password), m_password, "Password to be used for authentication with the service.", true, SettingScope.User); settings.Add(nameof(SerializationFormat), m_serializationFormat, "Message serialization format for interactions with service, one of: Xml, Json or Binary. Default is Binary."); settings.Add(nameof(StatusMessageFilter), m_statusMessageFilter, "Command used to negotiate status message filter when client connects to the ServiceHelper."); Username = settings[nameof(Username)].ValueAs(m_username); Password = settings[nameof(Password)].ValueAs(m_password); SerializationFormat = settings[nameof(SerializationFormat)].ValueAs(m_serializationFormat); StatusMessageFilter = settings[nameof(StatusMessageFilter)].ValueAs(m_statusMessageFilter); } } /// <summary> /// Connects <see cref="RemotingClient"/> to <see cref="ServiceHelper.RemotingServer"/> and wait until authentication is complete. /// </summary> public void Connect() { if ((object)m_remotingClient == null) throw new InvalidOperationException("RemotingClient property of ClientHelper component is not set"); m_authenticationComplete = false; // Wait for connection. m_remotingClient.Connect(); while (!m_authenticationComplete && m_remotingClient.Enabled) { // Wait for authentication. Thread.Sleep(100); // If remoting client has been disposed (and set to null) while sleeping, go ahead and exit... if ((object)m_remotingClient == null) return; } if (m_remotingClient.Enabled) m_attemptReconnection = true; } /// <summary> /// Disconnects <see cref="RemotingClient"/> from <see cref="ServiceHelper.RemotingServer"/>. /// </summary> public void Disconnect() { m_attemptReconnection = false; if ((object)m_remotingClient != null) m_remotingClient.Disconnect(); } /// <summary> /// Sends a request to the <see cref="ServiceHelper"/> using <see cref="RemotingClient"/>. /// </summary> /// <param name="request">Request text to be sent.</param> public void SendRequest(string request) { ClientRequest requestInstance = ClientRequest.Parse(request); if ((object)requestInstance != null) SendRequest(requestInstance); else UpdateStatus(UpdateType.Warning, "Request command \"{0}\" is invalid\r\n\r\n", request); } /// <summary> /// Sends a request to the <see cref="ServiceHelper"/> using <see cref="RemotingClient"/>. /// </summary> /// <param name="request"><see cref="ClientRequest"/> object to be sent.</param> public void SendRequest(ClientRequest request) { try { // Intercept TRANSFER requests for uploads. if (request.Command == "TRANSFER" && request.Arguments.Exists("upload")) { string source = FilePath.GetAbsolutePath(request.Arguments["orderedarg1"]); if (File.Exists(source)) { // Attach the file content. request.Attachments.Add(File.ReadAllBytes(source)); } else { // File does not exist. throw new FileNotFoundException(string.Format("File '{0}' does not exist", source)); } } // Pass the request along. m_remotingClient.SendAsync(request); } catch (Exception ex) { UpdateStatus(UpdateType.Alarm, "Error processing request - {0}", ex.Message); } } /// <summary> /// Raises the <see cref="ReceivedServiceUpdate"/> event. /// </summary> /// <param name="type">One of the <see cref="UpdateType"/> values.</param> /// <param name="update">Update message received.</param> protected virtual void OnReceivedServiceUpdate(UpdateType type, string update) { if ((object)ReceivedServiceUpdate != null) ReceivedServiceUpdate(this, new EventArgs<UpdateType, string>(type, update)); } /// <summary> /// Raises the <see cref="ReceivedServiceResponse"/> event. /// </summary> /// <param name="response"><see cref="ServiceResponse"/> received.</param> protected virtual void OnReceivedServiceResponse(ServiceResponse response) { if ((object)ReceivedServiceResponse != null) ReceivedServiceResponse(this, new EventArgs<ServiceResponse>(response)); } /// <summary> /// Raises the <see cref="ServiceStateChanged"/> event. /// </summary> /// <param name="state">New <see cref="ServiceState"/>.</param> protected virtual void OnServiceStateChanged(ObjectState<ServiceState> state) { if ((object)ServiceStateChanged != null) ServiceStateChanged(this, new EventArgs<ObjectState<ServiceState>>(state)); } /// <summary> /// Raises the <see cref="ProcessStateChanged"/> event. /// </summary> /// <param name="state">New <see cref="ServiceProcessState"/>.</param> protected virtual void OnProcessStateChanged(ObjectState<ServiceProcessState> state) { if ((object)ProcessStateChanged != null) ProcessStateChanged(this, new EventArgs<ObjectState<ServiceProcessState>>(state)); } /// <summary> /// Raises the <see cref="AuthenticationSuccess"/> event. /// </summary> protected virtual void OnAuthenticationSuccess() { if ((object)AuthenticationSuccess != null) AuthenticationSuccess(this, EventArgs.Empty); m_authenticationComplete = true; } /// <summary> /// Raises the <see cref="AuthenticationFailure"/> event. /// </summary> protected virtual void OnAuthenticationFailure() { CancelEventArgs args = new CancelEventArgs(true); if ((object)AuthenticationFailure != null) AuthenticationFailure(this, args); // Continue connection attempts if requested. if (args.Cancel) { m_attemptReconnection = false; m_authenticationComplete = true; } } /// <summary> /// Raises the <see cref="TelnetSessionEstablished"/> event. /// </summary> protected virtual void OnTelnetSessionEstablished() { if ((object)TelnetSessionEstablished != null) TelnetSessionEstablished(this, EventArgs.Empty); } /// <summary> /// Raises the <see cref="TelnetSessionTerminated"/> event. /// </summary> protected virtual void OnTelnetSessionTerminated() { if ((object)TelnetSessionTerminated != null) TelnetSessionTerminated(this, EventArgs.Empty); } /// <summary> /// Releases the unmanaged resources used by the <see cref="ClientHelper"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { if (!m_disposed) { try { // This will be done regardless of whether the object is finalized or disposed. if (disposing) { // This will be done only when the object is disposed by calling Dispose(). Disconnect(); SaveSettings(); if ((object)m_remotingClient != null) { // Detach events from any existing instance m_remotingClient.ConnectionEstablished -= RemotingClient_ConnectionEstablished; m_remotingClient.ConnectionAttempt -= RemotingClient_ConnectionAttempt; m_remotingClient.ConnectionException -= RemotingClient_ConnectionException; m_remotingClient.ConnectionTerminated -= RemotingClient_ConnectionTerminated; m_remotingClient.ReceiveDataComplete -= RemotingClient_ReceiveDataComplete; } } } finally { m_disposed = true; // Prevent duplicate dispose. base.Dispose(disposing); // Call base class Dispose(). } } } private void UpdateStatus(UpdateType type, string message, params object[] args) { OnReceivedServiceUpdate(type, string.Format(message, args)); } private void RemotingClient_ConnectionAttempt(object sender, EventArgs e) { UpdateStatus(UpdateType.Information, "Connecting to {0}...\r\n\r\n", m_remotingClient.ServerUri); } private void RemotingClient_ConnectionEstablished(object sender, EventArgs e) { // Upon establishing connection with the service's communication client, we'll send our information to the // service so the service can keep track of all the client that are connected to its communication server. m_remotingClient.SendAsync(new ClientInfo(this)); StringBuilder status = new StringBuilder(); status.AppendFormat("Connected to {0}:", m_remotingClient.ServerUri); status.AppendLine(); status.AppendLine(); status.Append(m_remotingClient.Status); status.AppendLine(); UpdateStatus(UpdateType.Information, "{0}", status.ToString()); SendRequest(StatusMessageFilter); } private void RemotingClient_ConnectionException(object sender, EventArgs<Exception> e) { StringBuilder status = new StringBuilder(); TcpClient tcpClient; TlsClient tlsClient; status.AppendFormat("Exception during connection attempt: {0}", e.Argument.Message); status.AppendLine(); status.AppendLine(); UpdateStatus(UpdateType.Alarm, "{0}", status.ToString()); tlsClient = m_remotingClient as TlsClient; if ((object)tlsClient != null) { tlsClient.NetworkCredential = null; } else { tcpClient = m_remotingClient as TcpClient; if ((object)tcpClient != null) tcpClient.NetworkCredential = null; } } private void RemotingClient_ConnectionTerminated(object sender, EventArgs e) { StringBuilder status = new StringBuilder(); status.AppendFormat("Disconnected from {0}:", m_remotingClient.ServerUri); status.AppendLine(); status.AppendLine(); status.Append(m_remotingClient.Status); status.AppendLine(); UpdateStatus(UpdateType.Warning, "{0}", status.ToString()); // Attempt reconnection on a separate thread. if (m_attemptReconnection) { new Thread(state => { Thread.Sleep(1000); Connect(); }) .Start(); } } private void RemotingClient_ReceiveDataComplete(object sender, EventArgs<byte[], int> e) { ServiceResponse response; Serialization.TryDeserialize(e.Argument1.BlockCopy(0, e.Argument2), m_serializationFormat, out response); if ((object)response != null) { switch (response.Type) { case "UPDATECLIENTSTATUS-INFORMATION": UpdateStatus(UpdateType.Information, "{0}", response.Message); break; case "UPDATECLIENTSTATUS-WARNING": UpdateStatus(UpdateType.Warning, "{0}", response.Message); break; case "UPDATECLIENTSTATUS-ALARM": UpdateStatus(UpdateType.Alarm, "{0}", response.Message); break; case "AUTHENTICATIONSUCCESS": OnAuthenticationSuccess(); break; case "AUTHENTICATIONFAILURE": OnAuthenticationFailure(); break; case "SERVICESTATECHANGED": if (response.Attachments.Count > 0) { ObjectState<ServiceState> state = response.Attachments[0] as ObjectState<ServiceState>; if ((object)state != null) { // Notify change in service state by raising an event. OnServiceStateChanged(state); // Provide a status update for change in state of the service. UpdateType type = UpdateType.Information; switch (state.CurrentState) { case ServiceState.Stopped: case ServiceState.Paused: case ServiceState.Shutdown: type = UpdateType.Warning; break; } UpdateStatus(type, "State of service \"{0}\" has changed to \"{1}\".\r\n\r\n", state.ObjectName, state.CurrentState); } } break; case "PROCESSSTATECHANGED": if (response.Attachments.Count > 0) { ObjectState<ServiceProcessState> state = response.Attachments[0] as ObjectState<ServiceProcessState>; if ((object)state != null) { // Notify change in process state by raising an event. OnProcessStateChanged(state); // Provide a status update for change in state of the service process. UpdateType type = UpdateType.Information; switch (state.CurrentState) { case ServiceProcessState.Aborted: case ServiceProcessState.Exception: type = UpdateType.Alarm; break; } UpdateStatus(type, "State of process \"{0}\" has changed to \"{1}\".\r\n\r\n", state.ObjectName, state.CurrentState); } } break; case "TELNETSESSION": switch (response.Message.ToUpper()) { case "ESTABLISHED": OnTelnetSessionEstablished(); break; case "TERMINATED": OnTelnetSessionTerminated(); break; } break; case "TRANSFER:SUCCESS": if (response.Attachments.Count == 2) { // Extract data from response. byte[] content = (byte[])response.Attachments[0]; Arguments arguments = (Arguments)response.Attachments[1]; string target = arguments["orderedarg2"]; bool overwrite = arguments.Exists("overwrite"); target = FilePath.GetAbsolutePath(target); if (!File.Exists(target) || overwrite) { // Save the received file. UpdateStatus(UpdateType.Information, "Saving file '{0}'...\r\n\r\n", target); File.WriteAllBytes(target, content); UpdateStatus(UpdateType.Information, "File '{0}' saved successfully.\r\n\r\n", target); } else { // File exists and cannot be overwritten. UpdateStatus(UpdateType.Alarm, "File '{0}' already exists.\r\n\r\n", target); } } else { // Response is malformed. UpdateStatus(UpdateType.Alarm, "{0} response is malformed.\r\n\r\n", response.Type); } break; default: OnReceivedServiceResponse(response); break; } } } #endregion #region [ Static ] /// <summary> /// Returns an <see cref="ClientRequestInfo"/> object for the specified <paramref name="requestCommand"/> that can be used /// to invoke <see cref="ServiceHelper.ClientRequestHandlers"/> manually as if the request was sent by a <see cref="ClientHelper"/> remotely. /// </summary> /// <param name="requestCommand">Command for which an <see cref="ClientRequestInfo"/> object is to be created.</param> /// <returns>An <see cref="ClientRequestInfo"/> object.</returns> public static ClientRequestInfo PretendRequest(string requestCommand) { ClientRequest request = ClientRequest.Parse(requestCommand); ClientRequestInfo requestInfo = new ClientRequestInfo(new ClientInfo(), request); return requestInfo; } /// <summary> /// Attempts to parse an actionable response sent from the service. /// </summary> /// <param name="serviceResponse"><see cref="ServiceResponse"/> to test for actionable response.</param> /// <param name="sourceCommand">Command that invoked <paramref name="serviceResponse"/>.</param> /// <param name="responseSuccess">Boolean success state of <paramref name="serviceResponse"/>.</param> /// <returns><c>true</c> if actionable response was able to be parsed successfully; otherwise <c>false</c>.</returns> public static bool TryParseActionableResponse(ServiceResponse serviceResponse, out string sourceCommand, out bool responseSuccess) { bool parseSucceeded = false; sourceCommand = null; responseSuccess = false; try { string response = serviceResponse.Type; // Attempt to parse response message if (!string.IsNullOrWhiteSpace(response)) { // Response types are formatted as "Command:Success" or "Command:Failure" string[] parts = response.Split(':'); if (parts.Length > 1) { sourceCommand = parts[0].Trim().ToTitleCase(); responseSuccess = (string.Compare(parts[1].Trim(), "Success", StringComparison.OrdinalIgnoreCase) == 0); parseSucceeded = true; } } } catch { parseSucceeded = false; } return parseSucceeded; } #endregion } }