private void OnMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { try { using (ThreadLock.Lock(myResponseReceiverContexts)) { TResponseReceiverContext aResponseReceiver = GetResponseReceiver(e.ResponseReceiverId); if (aResponseReceiver == null) { // Note: the response receiver was just disconnected. return; } aResponseReceiver.LastReceiveTime = DateTime.Now; } // Deserialize the incoming message. MonitorChannelMessage aMessage = mySerializer.Deserialize <MonitorChannelMessage>(e.Message); // if the message is ping, then response. if (aMessage.MessageType == MonitorChannelMessageType.Message) { // Notify the incoming message. DuplexChannelMessageEventArgs aMsg = new DuplexChannelMessageEventArgs(e.ChannelId, aMessage.MessageContent, e.ResponseReceiverId, e.SenderAddress); Dispatcher.Invoke(() => NotifyGeneric(MessageReceived, aMsg, true)); } } catch (Exception err) { EneterTrace.Error(TracedObject + ErrorHandler.FailedToReceiveMessage, err); } } }
protected override void OnRequestMessageReceived(object sender, DuplexChannelMessageEventArgs e) { if (MessageReceived != null) { MessageReceived(sender, e); } }
private void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { byte[] aVideoData = (byte[])e.Message; // Forward received data to the named pipe so that VLC can process it. videoPipe.WriteAsync(aVideoData, 0, aVideoData.Length); }
/// <summary> /// The method is called when a message from the attached duplex input channel is received. /// The received message is wrapped and sent to the duplex output channel. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void OnMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { if (!IsDuplexOutputChannelAttached) { EneterTrace.Error(TracedObject + "is not attached to the duplex output channel."); return; } try { using (ThreadLock.Lock(myDuplexInputChannels)) { myDuplexInputChannels[e.ChannelId].ResponseReceiverId = e.ResponseReceiverId; } ISerializer aSerializer = mySerializer.ForResponseReceiver(e.ResponseReceiverId); object aMessage = DataWrapper.Wrap(e.ChannelId, e.Message, aSerializer); AttachedDuplexOutputChannel.SendMessage(aMessage); } catch (Exception err) { EneterTrace.Error(TracedObject + "failed to send the message to the duplex output channel '" + e.ChannelId + "'.", err); } } }
private void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { try { // Deserialize the message. MonitorChannelMessage aMessage = mySerializer.Deserialize <MonitorChannelMessage>(e.Message); // Note: timer setting is after deserialization. // reason: if deserialization fails the timer is not updated and the client will be disconnected. using (ThreadLock.Lock(myConnectionManipulatorLock)) { // Cancel the current response timeout and set the new one. myReceiveTimer.Change(myReceiveTimeout); } // If it is a message. if (aMessage.MessageType == MonitorChannelMessageType.Message) { Dispatcher.Invoke(() => Notify <DuplexChannelMessageEventArgs>(ResponseMessageReceived, new DuplexChannelMessageEventArgs(e.ChannelId, aMessage.MessageContent, e.ResponseReceiverId, e.SenderAddress), true)); } } catch (Exception err) { EneterTrace.Error(TracedObject + ErrorHandler.FailedToReceiveMessage, err); } } }
protected override void OnRequestMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { if (MessageReceived == null) { EneterTrace.Warning(TracedObject + ErrorHandler.NobodySubscribedForMessage); return; } TypedRequestReceivedEventArgs <_RequestType> aRequestReceivedEventArgs = null; try { _RequestType aRequestMessage = mySerializer.ForResponseReceiver(e.ResponseReceiverId).Deserialize <_RequestType>(e.Message); aRequestReceivedEventArgs = new TypedRequestReceivedEventArgs <_RequestType>(e.ResponseReceiverId, e.SenderAddress, aRequestMessage); } catch (Exception err) { EneterTrace.Warning(TracedObject + "failed to deserialize the request message.", err); aRequestReceivedEventArgs = new TypedRequestReceivedEventArgs <_RequestType>(e.ResponseReceiverId, e.SenderAddress, err); } try { MessageReceived(this, aRequestReceivedEventArgs); } catch (Exception err) { EneterTrace.Warning(TracedObject + ErrorHandler.DetectedException, err); } } }
protected override void OnRequestMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { if (RequestReceived == null) { EneterTrace.Warning(TracedObject + ErrorHandler.NobodySubscribedForMessage); return; } if (e.Message is string == false) { string anErrorMessage = TracedObject + "failed to receive the request message because the message is not string."; EneterTrace.Error(anErrorMessage); return; } try { RequestReceived(this, new StringRequestReceivedEventArgs((string)e.Message, e.ResponseReceiverId, e.SenderAddress)); } catch (Exception err) { EneterTrace.Warning(TracedObject + ErrorHandler.DetectedException, err); } } }
protected void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { if (ResponseMessageReceived != null) { ResponseMessageReceived(this, e); } }
private void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { Notify <DuplexChannelMessageEventArgs>(ResponseMessageReceived, e, true); } }
protected override void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { if (BrokerMessageReceived == null) { EneterTrace.Warning(TracedObject + ErrorHandler.NobodySubscribedForMessage); return; } BrokerMessageReceivedEventArgs anEvent = null; try { BrokerMessage aMessage = mySerializer.ForResponseReceiver(e.ResponseReceiverId).Deserialize <BrokerMessage>(e.Message); anEvent = new BrokerMessageReceivedEventArgs(aMessage.MessageTypes[0], aMessage.Message); } catch (Exception err) { EneterTrace.Warning(TracedObject + "failed to deserialize the request message.", err); anEvent = new BrokerMessageReceivedEventArgs(err); } try { BrokerMessageReceived(this, anEvent); } catch (Exception err) { EneterTrace.Warning(TracedObject + ErrorHandler.DetectedException, err); } } }
// A message from the client was received. private void OnMessageFromClientReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { MessageBusMessage aMessageBusMessage; try { aMessageBusMessage = mySerializer.Deserialize <MessageBusMessage>(e.Message); } catch (Exception err) { EneterTrace.Error(TracedObject + "failed to deserialize message from service. The service will be disconnected.", err); UnregisterClient(e.ResponseReceiverId, true, true); return; } if (aMessageBusMessage.Request == EMessageBusRequest.ConnectClient) { EneterTrace.Debug("CLIENT OPENS CONNECTION TO '" + aMessageBusMessage.Id + "'."); RegisterClient(e.ResponseReceiverId, aMessageBusMessage.Id); } else if (aMessageBusMessage.Request == EMessageBusRequest.SendRequestMessage) { ForwardMessageToService(e.ResponseReceiverId, aMessageBusMessage); } } }
/// <summary> /// Method is called when a response is received from the duplex output channel. /// It wrapps the response and sends the wrapped response to the correct response receiver as the response. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { try { // try to find the response receiver id where the wrapped message should be responded. TDuplexConnection aConnction = null; using (ThreadLock.Lock(myConnections)) { aConnction = myConnections.FirstOrDefault(x => x.DuplexOutputChannel == (IDuplexOutputChannel)sender); } if (aConnction != null) { ISerializer aSerializer = mySerializer.ForResponseReceiver(aConnction.ResponseReceiverId); object aMessage = DataWrapper.Wrap(e.ChannelId, e.Message, aSerializer); AttachedDuplexInputChannel.SendResponseMessage(aConnction.ResponseReceiverId, aMessage); } else { EneterTrace.Warning(TracedObject + "failed to send the response message because the response receiver id does not exist. It is possible the response receiver has already been disconnected."); } } catch (Exception err) { EneterTrace.Error(TracedObject + ErrorHandler.FailedToSendResponseMessage, err); } } }
private void NotifyMessageReceived(MessageContext messageContext, ProtocolMessage protocolMessage) { using (EneterTrace.Entering()) { DuplexChannelMessageEventArgs anEventArgs = new DuplexChannelMessageEventArgs(ChannelId, protocolMessage.Message, protocolMessage.ResponseReceiverId, messageContext.SenderAddress); NotifyGeneric <DuplexChannelMessageEventArgs>(MessageReceived, anEventArgs, true); } }
void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { lock (myReceivedResponses) { myReceivedResponses.Add((string)e.Message); myResponseMessageReceived.Set(); } }
void OnMessageReceived(object sender, DuplexChannelMessageEventArgs e) { lock (myReceivedMessages) { myReceivedMessages.Add((string)e.Message); myInputChannel.SendResponseMessage(e.ResponseReceiverId, "Response for " + (string)e.Message); } }
private void OnMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { // Note: this method is called from the underlying channel. Therefore it is called in the correct thread. Notify <DuplexChannelMessageEventArgs>(MessageReceived, e, true); } }
/// <summary> /// It is called when a message is received from a client connected to this Backup Router. /// The message will be forwarded to the connected service. /// If the sending fails the connection is considered broken it will try to reconnect with the next /// available service and send the message again. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected override void OnRequestMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { TConnection aConnection; using (ThreadLock.Lock(myConnectionsLock)) { // If the client does not have associated connection to the service behind the router create it. aConnection = myOpenConnections.FirstOrDefault(x => x.ResponseReceiverId == e.ResponseReceiverId); if (aConnection == null) { aConnection = OpenConnection(e.ResponseReceiverId); myOpenConnections.Add(aConnection); } try { aConnection.DuplexOutputChannel.SendMessage(e.Message); // The message was successfully sent. return; } catch (Exception err) { // Sending of the message failed. Therefore the connection is considered broken. EneterTrace.Warning(TracedObject + "failed to forward the message to " + aConnection.DuplexOutputChannel.ChannelId + ". The connection will be redirected.", err); } // Redirect and try to send again. try { // Close the broken connection. CloseConnection(aConnection); myOpenConnections.Remove(aConnection); // Set next available receiver. SetNextAvailableReceiver(); // Open the new connection. TConnection aNewConnection = OpenConnection(e.ResponseReceiverId); myOpenConnections.Add(aNewConnection); NotifyConnectionRedirected(aNewConnection.ResponseReceiverId, aConnection.DuplexOutputChannel.ChannelId, aNewConnection.DuplexOutputChannel.ChannelId); // Send the message via the new connection. aNewConnection.DuplexOutputChannel.SendMessage(e.Message); } catch (Exception err) { string aMessage = TracedObject + "failed to forward the message after the redirection"; EneterTrace.Error(aMessage, err); throw; } } } }
void Worker4504InputChannel_MessageReceived(object sender, DuplexChannelMessageEventArgs e) { // echo back //Logger.Info(BitConverter.ToString(e.Message as byte[])); //string s = BitConverter.ToString(e.Message as byte[]); //Logger.Info("Received : " + s); Logger.Info("Received data length : " + (e.Message as byte[]).Length); //Logger.Info(e.Message.ToString()); Worker4504InputChannel.SendResponseMessage(e.ResponseReceiverId, e.Message); }
void Worker4504_ResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { int length = (e.Message as byte[]).Length; Log("Worker received length : " + length); // download if (length != 0) { _packetCounter++; if (_packetCounter >= (_repeat - 1)) { _stopwatch.Stop(); Disconnect(); int sizeTransfered = _packetCounter * _bytesLength; double MBps = ((double)sizeTransfered / 1048576) / ((double)_stopwatch.ElapsedMilliseconds / 1000); double Mbps = (((double)sizeTransfered * 8) / 1000000) / ((double)_stopwatch.ElapsedMilliseconds / 1000); Log("Received completed."); Log("Total packets : " + _packetCounter); // should equals to repeat Log("Packets length : " + _bytesLength + " bytes"); Log("Duration : " + _stopwatch.ElapsedMilliseconds + " ms"); Log("Size transfered : " + sizeTransfered + " bytes"); Log("Bandwidth : " + MBps + " MB/s"); Log("Bandwidth : " + Mbps + " Mb/s"); Log(""); MiscUIStop((double)sizeTransfered / 1048576 + " megabytes of data downloaded in " + (double)_stopwatch.ElapsedMilliseconds / 1000 + " seconds"); _packetCounter = 0; } } // upload else if (length == 0) { _stopwatch.Stop(); Disconnect(); int sizeTransfered = _repeat * _bytesLength; double MBps = ((double)sizeTransfered / 1048576) / ((double)_stopwatch.ElapsedMilliseconds / 1000); double Mbps = (((double)sizeTransfered * 8) / 1000000) / ((double)_stopwatch.ElapsedMilliseconds / 1000); Log("Send completed."); Log("Total packets : " + _repeat); // should equals to repeat Log("Packets length : " + _bytesLength + " bytes"); Log("Duration : " + _stopwatch.ElapsedMilliseconds + " ms"); Log("Size transfered : " + sizeTransfered + " bytes"); Log("Bandwidth : " + MBps + " MB/s"); Log("Bandwidth : " + Mbps + " Mb/s"); Log(""); MiscUIStop((double)sizeTransfered / 1048576 + " megabytes of data uploaded in " + (double)_stopwatch.ElapsedMilliseconds / 1000 + " seconds"); } }
void Worker4504OutputChannel_ResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { Log("Received data length : " + (e.Message as byte[]).Length); Log("ChannelId : " + e.ChannelId); //string s = BitConverter.ToString(e.Message as byte[]); //Log("Received : " + s); //Log("Received : " + e.Message.ToString()); //Log("Received : " + BitConverter.ToString(e.Message as byte[])); //Worker4504OutputChannel.SendMessage(e.Message); }
protected override void OnMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { using (ThreadLock.Lock(myConnections)) { IEnumerable <TConnection> aConfiguredConnections = myConnections.Where(x => x.DuplexInputChannelId == e.ChannelId); foreach (TConnection aConnection in aConfiguredConnections) { SendMessage(aConnection.DuplexInputChannelId, e.ResponseReceiverId, aConnection.DuplexOutputChannelId, e.Message); } } } }
private void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { lock (myReceivedMessages) { myReceivedMessages.Add(e); if (myReceivedMessages.Count == myNumberOfExpectedResponseMessages) { myResponseMessagesReceivedEvent.Set(); } } } }
// When client received a message from an output connection. private void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { try { myInputChannel.SendResponseMessage(myInputResponseReceiverId, e.Message); } catch (Exception err) { EneterTrace.Warning("Failed to send message via the input channel '" + myInputChannel.ChannelId + "'.", err); } } }
protected override void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { try { SendResponseMessage(e.ResponseReceiverId, e.Message); } catch { // Nothing to do because the error was already traced. } } }
private void OnMessageFromMessageBusReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { MessageBusMessage aMessageBusMessage; try { aMessageBusMessage = mySerializer.Deserialize <MessageBusMessage>(e.Message); } catch (Exception err) { EneterTrace.Error(TracedObject + "failed to deserialize message.", err); return; } if (aMessageBusMessage.Request == EMessageBusRequest.ConfirmClient) { // Indicate the connection is open and relase the waiting in the OpenConnection(). myOpenConnectionConfirmed.Set(); EneterTrace.Debug("CONNECTION CONFIRMED"); } else if (aMessageBusMessage.Request == EMessageBusRequest.SendResponseMessage) { Action <MessageContext> aResponseHandler = myResponseMessageHandler; if (aResponseHandler != null) { ProtocolMessage aProtocolMessage = new ProtocolMessage(EProtocolMessageType.MessageReceived, myServiceId, aMessageBusMessage.MessageData); MessageContext aMessageContext = new MessageContext(aProtocolMessage, e.SenderAddress); try { aResponseHandler(aMessageContext); } catch (Exception err) { EneterTrace.Warning(TracedObject + ErrorHandler.DetectedException, err); } } } } }
protected override void OnRequestMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { TClient aClient; using (ThreadLock.Lock(myClientConnectionLock)) { myConnectedClients.TryGetValue(e.ResponseReceiverId, out aClient); } if (aClient != null) { aClient.ForwardMessage(e.Message); } else { EneterTrace.Warning(TracedObject + "failed to forward the message because ResponseReceiverId '" + e.ResponseReceiverId + "' was not found among open connections."); } } }
void Worker4504_Received(object sender, DuplexChannelMessageEventArgs e) { // echo back //Logger.Info(BitConverter.ToString(e.Message as byte[])); //string s = BitConverter.ToString(e.Message as byte[]); //Logger.Info("Received : " + s); //Logger.Info(e.Message.ToString()); //Worker4504InputChannel.SendResponseMessage(e.ResponseReceiverId, e.Message); int length = (e.Message as byte[]).Length; Logger.Info("Worker received length : " + length); if (length == 0) { // notify client to that we received the last byte var b = new byte[0]; Worker4504_InputChannel.SendResponseMessage(e.ResponseReceiverId, b); } }
/// <summary> /// It is called when a response message from the service is received. /// The response message must be redirected to the associated client. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void OnOutputChannelResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { string aResponseReceiverId = null; using (ThreadLock.Lock(myConnectionsLock)) { TConnection aConnection = myOpenConnections.FirstOrDefault(x => x.DuplexOutputChannel.ResponseReceiverId == e.ResponseReceiverId); if (aConnection != null) { aResponseReceiverId = aConnection.ResponseReceiverId; } } if (aResponseReceiverId == null) { EneterTrace.Warning(TracedObject + "could not find receiver for the incoming response message."); return; } using (ThreadLock.Lock(myDuplexInputChannelManipulatorLock)) { // Send the response message via the duplex input channel to the sender. if (AttachedDuplexInputChannel != null) { try { AttachedDuplexInputChannel.SendResponseMessage(aResponseReceiverId, e.Message); } catch (Exception err) { EneterTrace.Error(TracedObject + ErrorHandler.FailedToSendResponseMessage, err); } } else { EneterTrace.Error(TracedObject + "cannot send the response message when the duplex input channel is not attached."); } } } }
/// <summary> /// The method is called when a reponse message is received from the duplex output channel. /// The received response is unwrapped and sent as a response to the matching duplex input channel. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected override void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { try { ISerializer aSerializer = mySerializer.ForResponseReceiver(e.ResponseReceiverId); WrappedData aWrappedData = DataWrapper.Unwrap(e.Message, aSerializer); // WrappedData.AddedData represents the channel id. // Therefore if everything is ok then it must be string. if (aWrappedData.AddedData is string) { // Get the output channel according to the channel id. TDuplexInputChannel aDuplexInputChannel = null; using (ThreadLock.Lock(myDuplexInputChannels)) { myDuplexInputChannels.TryGetValue((string)aWrappedData.AddedData, out aDuplexInputChannel); } if (aDuplexInputChannel != null) { aDuplexInputChannel.DuplexInputChannel.SendResponseMessage(aDuplexInputChannel.ResponseReceiverId, aWrappedData.OriginalData); } else { EneterTrace.Warning(TracedObject + "could not send the response message to the duplex input channel '" + (string)aWrappedData.AddedData + "' because the channel is not attached to the unwrapper."); } } else { EneterTrace.Error(TracedObject + "detected that the unwrapped message does not contain the channel id as the string type."); } } catch (Exception err) { EneterTrace.Error(TracedObject + "failed to process the response message.", err); } } }
private void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { if (ResponseMessageReceived != null) { try { ResponseMessageReceived(this, new DuplexChannelMessageEventArgs(ChannelId, e.Message, ResponseReceiverId, "")); } catch (Exception err) { EneterTrace.Warning(TracedObject + ErrorHandler.DetectedException, err); } } else { EneterTrace.Warning(TracedObject + ErrorHandler.NobodySubscribedForMessage); } } }
void Worker4504_ResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { int length = (e.Message as byte[]).Length; Log("Worker received length : " + length); // download if (length != 0) { _packetCounter++; if (_packetCounter >= (_repeat - 1)) { _stopwatch.Stop(); Disconnect(); int sizeTransfered = _packetCounter * _bytesLength; double MBps = ((double)sizeTransfered / 1048576) / ((double)_stopwatch.ElapsedMilliseconds / 1000); double Mbps = (((double)sizeTransfered * 8) / 1000000) / ((double)_stopwatch.ElapsedMilliseconds / 1000); double duration = _stopwatch.ElapsedMilliseconds / 1000.0; Log("Received completed."); Log("Total packets : " + _packetCounter); // should equals to repeat Log("Packets length : " + _bytesLength + " bytes"); Log("Duration : " + _stopwatch.ElapsedMilliseconds + " ms"); Log("Size transfered : " + sizeTransfered + " bytes"); Log("Bandwidth : " + MBps + " MB/s"); Log("Bandwidth : " + Mbps + " Mb/s"); Log(""); //MiscUIStop((double)sizeTransfered / 1048576 + " megabytes of data downloaded in " + (double)_stopwatch.ElapsedMilliseconds / 1000 + " seconds with average download speed of " + Mbps + " megabits per second"); MiscUIStop((double)sizeTransfered / 1048576 + " megabytes of data downloaded in " + (double)_stopwatch.ElapsedMilliseconds / 1000 + " seconds" ); HtmlPage.Window.Invoke("ProcessDownloadResults", Mbps, duration); _packetCounter = 0; } } // upload else if (length == 0) { _stopwatch.Stop(); Disconnect(); int sizeTransfered = _repeat * _bytesLength; double MBps = ((double)sizeTransfered / 1048576) / ((double)_stopwatch.ElapsedMilliseconds / 1000); double Mbps = (((double)sizeTransfered * 8) / 1000000) / ((double)_stopwatch.ElapsedMilliseconds / 1000); double duration = _stopwatch.ElapsedMilliseconds / 1000.0; Log("Send completed."); Log("Total packets : " + _repeat); // should equals to repeat Log("Packets length : " + _bytesLength + " bytes"); Log("Duration : " + _stopwatch.ElapsedMilliseconds + " ms"); Log("Size transfered : " + sizeTransfered + " bytes"); Log("Bandwidth : " + MBps + " MB/s"); Log("Bandwidth : " + Mbps + " Mb/s"); Log(""); //MiscUIStop((double)sizeTransfered / 1048576 + " megabytes of data uploaded in " + (double)_stopwatch.ElapsedMilliseconds / 1000 + " seconds with average upload speed of " + Mbps + " megabits per second"); MiscUIStop((double)sizeTransfered / 1048576 + " megabytes of data uploaded in " + (double)_stopwatch.ElapsedMilliseconds / 1000 + " seconds"); HtmlPage.Window.Invoke("ProcessUploadResults", Mbps, duration); } }