/// <summary> /// Handle command message: a clinet ping. /// </summary> private AmfGenericMessage HandleClientPing(AmfGenericMessage request, CommandMessage message) { var acknowledge = AmfOperationUtil.BuildAcknowledgeMessage(message); acknowledge.Headers = new Dictionary<string, object> { {CommandMessageHeader.MessagingVersion, Capabilities.MessagingVersion} }; return AmfOperationUtil.BuildMessageReply(request, acknowledge); }
/// <summary> /// Build a message reply. /// </summary> /// <param name="request">Request message.</param> /// <param name="body">Reply message's body.</param> public static AmfGenericMessage BuildMessageReply(AmfGenericMessage request, object body) { var replyHeaders = new Dictionary<string, AmfHeader>(); var replyMessage = new AmfMessage { Target = CreateResultReplyTarget(request.AmfMessage), Response = string.Empty, Data = body }; return new AmfGenericMessage(replyHeaders, replyMessage); }
/// <summary> /// Process an AMF command request. /// </summary> /// <param name="request">Request message to process.</param> /// <returns>Service reply message.</returns> protected AmfGenericMessage ProcessCommand(AmfGenericMessage request) { var command = (CommandMessage)request.AmfMessage.Data; Func<AmfGenericMessage, CommandMessage, AmfGenericMessage> handler; switch (command.Operation) { case CommandMessageOperation.ClientPing: handler = HandleClientPing; break; default: throw new NotSupportedException(string.Format(Errors.AmfCommandInvoker_ProcessCommand_OperationNotSupported, command.Operation)); } return handler.Invoke(request, command); }
public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { //An internal server error occured if (OperationContext.Current == null) return; //An AMF operation if (OperationContext.Current.IncomingMessageProperties.ContainsKey(MessagingHeaders.InvokerMessageBody)) { var replyHeaders = new Dictionary<string, AmfHeader>(); var replyMessage = new AmfMessage { Response = string.Empty }; var requestMessage = (AmfMessage)OperationContext.Current.IncomingMessageProperties[MessagingHeaders.InvokerMessageBody]; //An RPC operation if (OperationContext.Current.IncomingMessageProperties.ContainsKey(MessagingHeaders.RemotingMessage)) { var rpcMessage = (RemotingMessage)OperationContext.Current.IncomingMessageProperties[MessagingHeaders.RemotingMessage]; var acknowledge = AmfOperationUtil.BuildErrorMessage(rpcMessage); if (acknowledge.Headers == null) acknowledge.Headers = new Dictionary<string, object>(); if (error is AmfOperationNotFoundException) acknowledge.Headers[AmfMessageHeader.StatusCode] = (int)HttpStatusCode.NotFound; else acknowledge.Headers[AmfMessageHeader.StatusCode] = (int)HttpStatusCode.BadRequest; acknowledge.FaultCode = ErrorMessageFaultCode.DeliveryInDoubt; acknowledge.FaultString = error.Message; if (_capabilities.ExceptionDetailInFaults) { acknowledge.FaultDetail = error.StackTrace; } //Get FaultException's detail object, if any if(error is FaultException) { var type = error.GetType(); if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(FaultException<>))) { acknowledge.ExtendedData = type.GetProperty("Detail").GetValue(error, null); } } replyMessage.Target = AmfOperationUtil.CreateStatusReplyTarget(requestMessage); replyMessage.Data = acknowledge; } fault = new AmfGenericMessage(replyHeaders, replyMessage); } }
/// <summary> /// Deserializes a message into an array of parameters. /// </summary> /// <param name="message">The incoming message.</param> /// <param name="parameters">The objects that are passed to the operation as parameters.</param> public virtual void DeserializeRequest(Message message, object[] parameters) { var request = (AmfGenericMessage)message; parameters[0] = new AmfGenericMessage(request.AmfHeaders, request.AmfMessage); //Use space allocated for one AmfGenericMessage }
/// <summary> /// Selects the service operation to call. /// </summary> /// <param name="message">The <c>Message</c> object sent to invoke a service operation.</param> /// <returns>The name of the service operation to call.</returns> public string SelectOperation(ref Message message) { AmfPacket packet; //Read AMF packet from the message try { packet = message.GetBody<AmfPacket>(_context.AmfSerializer); } finally { message.Close(); } //Batch request if (packet.Messages.Count > 1) { message = new AmfBatchMessage(packet.Headers, packet.Messages); return AmfOperationKind.Batch; } //Regular request var amfMessage = new AmfGenericMessage(packet.Headers, packet.Messages[0]); message = amfMessage; //Check if it is a Flex message. //Due to the nature of NetConnection.call(), RPC arguments //are sent in an array. But in case of AMFX, an array is not used //if there is only one argument. var arraybody = amfMessage.AmfMessage.Data as object[]; AbstractMessage flexmessage; if (arraybody != null && arraybody.Length > 0) flexmessage = arraybody[0] as AbstractMessage; else flexmessage = amfMessage.AmfMessage.Data as AbstractMessage; //It is a Flex message after all if (flexmessage != null) { amfMessage.AmfMessage.Data = flexmessage; var type = flexmessage.GetType(); //An RPC operation if (type == typeof(RemotingMessage)) { var operation = ((RemotingMessage)flexmessage).Operation; return EndpointHasOperation(_context.ServiceEndpoint, operation) ? operation : AmfOperationKind.Fault; } //A Flex command message if (type == typeof(CommandMessage)) { return AmfOperationKind.Command; } } //If it's not a Flex message, then do it the old way return EndpointHasOperation(_context.ServiceEndpoint, amfMessage.AmfMessage.Target) ? amfMessage.AmfMessage.Target : AmfOperationKind.Fault; }