/// <summary>
        /// Sends a message to a remote server.
        /// </summary>
        /// <param name="action">The action to perform.</param>
        /// <param name="request">The request to send to the server.</param>
        /// <returns>The response from the server.</returns>
        public Response SendMessage(string action, ServerRequest request)
        {
            // Make sure there is a password
            if ((cryptoKey.Length == 0) || (cryptoIv.Length == 0))
            {
                InitialisePassword();
            }

            // Generate the encrypted request
            var encryptedRequest = new EncryptedRequest();

            encryptedRequest.Action = action;
            var crypto = new RijndaelManaged();

            crypto.Key = cryptoKey;
            crypto.IV  = cryptoIv;
            encryptedRequest.EncryptedData = EncryptMessage(crypto, request.ToString());

            // Send the request
            var response          = innerConnection.SendMessage("ProcessSecureRequest", encryptedRequest);
            var encryptedResponse = response as EncryptedResponse;

            // Generate the actual response
            if ((response.Result == ResponseResult.Success) && (encryptedResponse != null))
            {
                var data = DecryptMessage(crypto, encryptedResponse.EncryptedData);
                response = XmlConversionUtil.ProcessResponse(data);
            }
            return(response);
        }
        /// <summary>
        /// Processes a message.
        /// </summary>
        /// <param name="action">The action to use.</param>
        /// <param name="message">The request message in an XML format.</param>
        /// <returns>The response message in an XML format.</returns>
        public override string ProcessMessage(string action, string message)
        {
            Response response = new Response();

            try
            {
                // Find the type of message
                var messageXml = new XmlDocument();
                messageXml.LoadXml(message);
                var messageType = XmlConversionUtil.FindMessageType(messageXml.DocumentElement.Name);
                if (messageType == null)
                {
                    response.Result = ResponseResult.Failure;
                    response.ErrorMessages.Add(
                        new ErrorMessage(
                            string.Format(
                                CultureInfo.CurrentCulture, "Unable to translate message: '{0}' is unknown",
                                messageXml.DocumentElement.Name)));
                }

                // Convert the message and invoke the action
                var request = XmlConversionUtil.ConvertXmlToObject(messageType, message);
                response = connection.SendMessage(action, request as ServerRequest);
            }
            catch (Exception error)
            {
                response.Result = ResponseResult.Failure;
                response.ErrorMessages.Add(
                    new ErrorMessage("Unable to process error: " + error.Message));
            }

            return(response.ToString());
        }
        /// <summary>
        /// Converts a message string into a request.
        /// </summary>
        /// <param name="message">The XML of the message.</param>
        /// <returns>The converted <see cref="ServerRequest"/>.</returns>
        public static ServerRequest ConvertXmlToRequest(string message)
        {
            var messageXml = new XmlDocument();

            messageXml.LoadXml(message);
            var messageType = XmlConversionUtil.FindMessageType(messageXml.DocumentElement.Name);

            if (messageType == null)
            {
                throw new CommunicationsException("Unknown message type");
            }

            var request = ConvertXmlToObject(messageType, message) as ServerRequest;

            return(request);
        }
        /// <summary>
        /// Sends a message via HTTP.
        /// </summary>
        /// <param name="action"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        public Response SendMessage(string action, ServerRequest request)
        {
            // Generate the target URI
            Uri targetAddress = GenerateTargetUri(request);

            // Build the request and send it
            var client = this.WebClientfactory.Generate();
            NameValueCollection formData = new NameValueCollection();

            formData.Add("action", action);
            formData.Add("message", request.ToString());
            FireRequestSending(action, request);
            string response = Encoding.UTF8.GetString(client.UploadValues(targetAddress, "POST", formData));

            // Convert the response into a response object
            Response result = XmlConversionUtil.ProcessResponse(response);

            FireResponseReceived(action, result);
            return(result);
        }
        /// <summary>
        /// Sends a message to a remote server asychronously.
        /// </summary>
        /// <param name="action">The action to perform.</param>
        /// <param name="request">The request to send to the server.</param>
        /// <param name="userState">Any user state data.</param>
        public virtual void SendMessageAsync(string action, ServerRequest request, object userState)
        {
            // Ensure that async is only called once (or once with the user state)
            lock (lockObject)
            {
                if (userState == null)
                {
                    if (isBusy)
                    {
                        throw new InvalidOperationException();
                    }
                    isBusy = true;
                }
                else if (asyncOperations.ContainsKey(userState))
                {
                    if (asyncOperations.ContainsKey(userState))
                    {
                        throw new ArgumentException("Duplicate userState", "userState");
                    }
                }
            }

            // Initialise the web client
            var client = this.WebClientfactory.Generate();

            client.UploadValuesCompleted += (o, e) =>
            {
                if (SendMessageCompleted != null)
                {
                    if ((e.Error == null) && !e.Cancelled)
                    {
                        // Convert the response into a response object
                        string   response = Encoding.UTF8.GetString(e.Data);
                        Response result   = XmlConversionUtil.ProcessResponse(response);

                        MessageReceivedEventArgs args = new MessageReceivedEventArgs(result, null, false, userState);
                        SendMessageCompleted(this, args);
                    }
                    else
                    {
                        MessageReceivedEventArgs args = new MessageReceivedEventArgs(null, e.Error, e.Cancelled, userState);
                        SendMessageCompleted(this, args);
                    }
                }
                CompleteAsyncCall(userState);
            };
            lock (lockObject)
            {
                asyncOperations.Add(userState ?? string.Empty, client);
            }

            try
            {
                // Generate the target URI
                Uri targetAddress = GenerateTargetUri(request);

                // Build the request and send it
                NameValueCollection formData = new NameValueCollection();
                formData.Add("action", action);
                formData.Add("message", request.ToString());
                client.UploadValuesAsync(targetAddress, "POST", formData);
            }
            catch (Exception error)
            {
                if (SendMessageCompleted != null)
                {
                    MessageReceivedEventArgs args = new MessageReceivedEventArgs(null, error, false, userState);
                    SendMessageCompleted(this, args);
                }
                CompleteAsyncCall(userState);
            }
        }