//---------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------- namespace System.ServiceModel.Activities { using System; using System.Runtime; using System.Runtime.Serialization; using System.ServiceModel.Description; using System.Xml; using System.Xml.Serialization; static class MessageBuilder { static Type messageContractAttributeType; static XsdDataContractExporter xsdDataContractExporter; static XmlReflectionImporter xmlReflectionImporter; public static Type MessageContractAttributeType { get { if (messageContractAttributeType == null) { messageContractAttributeType = typeof(MessageContractAttribute); } return messageContractAttributeType; } } public static XsdDataContractExporter XsdDataContractExporter { get { if (xsdDataContractExporter == null) { xsdDataContractExporter = new XsdDataContractExporter(); } return xsdDataContractExporter; } } public static XmlReflectionImporter XmlReflectionImporter { get { if (xmlReflectionImporter == null) { xmlReflectionImporter = new XmlReflectionImporter(); } return xmlReflectionImporter; } } public static MessageDescription CreateMessageDescription(OperationDescription operation, bool isResponse, MessageDirection direction, string overridingAction, Type type, SerializerOption serializerOption) { MessageDescription result; if (type != null && IsMessageContract(type)) { result = CreateFromMessageContract(operation, isResponse, direction, overridingAction, type); } else { // For Send/Receive, we do not wrap message result = CreateEmptyMessageDescription(operation, isResponse, direction, overridingAction); AddMessagePartDescription(operation, isResponse, result, type, serializerOption); } return result; } public static MessageDescription CreateMessageDescription(OperationDescription operation, bool isResponse, MessageDirection direction, string overridingAction, string[] argumentNames, Type[] argumentTypes) { MessageDescription result; if (argumentTypes.Length == 1 && argumentTypes[0] == MessageDescription.TypeOfUntypedMessage) { result = CreateEmptyMessageDescription(operation, isResponse, direction, overridingAction); AddMessagePartDescription(operation, isResponse, result, argumentNames, argumentTypes); } else if (argumentTypes.Length == 1 && IsMessageContract(argumentTypes[0])) { result = CreateFromMessageContract(operation, isResponse, direction, overridingAction, argumentTypes[0]); } else { // For SendParameters/ReceiveParameters, we wrap for non-Message cases result = CreateEmptyMessageDescription(operation, isResponse, direction, overridingAction); AddMessagePartDescription(operation, isResponse, result, argumentNames, argumentTypes); SetWrapperName(operation, isResponse, result); } return result; } public static bool IsMessageContract(Type type) { if (type == null) { return false; } else { return type.IsDefined(MessageContractAttributeType, false); } } public static MessageDescription CreateFromMessageContract(OperationDescription operation, bool isResponse, MessageDirection direction, string overridingAction, Type messageContractType) { string action = overridingAction ?? NamingHelper.GetMessageAction(operation, isResponse); // TypeLoader typeLoader = new TypeLoader(); return typeLoader.CreateTypedMessageDescription(messageContractType, null, null, operation.DeclaringContract.Namespace, action, direction); } public static MessageDescription CreateEmptyMessageDescription(OperationDescription operation, bool isResponse, MessageDirection direction, string overridingAction) { string action = overridingAction ?? NamingHelper.GetMessageAction(operation, isResponse); MessageDescription result = new MessageDescription(action, direction); // Clear message wrapper result.Body.WrapperName = null; result.Body.WrapperNamespace = null; return result; } public static void AddMessagePartDescription(OperationDescription operation, bool isResponse, MessageDescription message, Type type, SerializerOption serializerOption) { if (type != null) { string partName; string partNamespace; if (serializerOption == SerializerOption.DataContractSerializer) { XmlQualifiedName xmlQualifiedName = XsdDataContractExporter.GetRootElementName(type); if (xmlQualifiedName == null) { xmlQualifiedName = XsdDataContractExporter.GetSchemaTypeName(type); } if (!xmlQualifiedName.IsEmpty) { partName = xmlQualifiedName.Name; partNamespace = xmlQualifiedName.Namespace; } else { // For anonymous type, we assign CLR type name and contract namespace to MessagePartDescription partName = type.Name; partNamespace = operation.DeclaringContract.Namespace; } } else { XmlTypeMapping xmlTypeMapping = XmlReflectionImporter.ImportTypeMapping(type); partName = xmlTypeMapping.ElementName; partNamespace = xmlTypeMapping.Namespace; } MessagePartDescription messagePart = new MessagePartDescription(NamingHelper.XmlName(partName), partNamespace) { Index = 0, Type = type // We do not infer MessagePartDescription.ProtectionLevel }; message.Body.Parts.Add(messagePart); } if (isResponse) { SetReturnValue(message, operation); } } public static void AddMessagePartDescription(OperationDescription operation, bool isResponse, MessageDescription message, string[] argumentNames, Type[] argumentTypes) { Fx.Assert(argumentNames != null && argumentTypes != null, "Argument cannot be null!"); Fx.Assert(argumentNames.Length == argumentTypes.Length, "Name and Type do not match!"); // Infer MessagePartDescription.Namespace from contract namespace string partNamespace = operation.DeclaringContract.Namespace; for (int index = 0; index < argumentNames.Length; index++) { // Infer MessagePartDescription.Name from parameter name string partName = argumentNames[index]; MessagePartDescription messagePart = new MessagePartDescription(NamingHelper.XmlName(partName), partNamespace) { Index = index, Type = argumentTypes[index] // We do not infer MessagePartDescription.ProtectionLevel }; message.Body.Parts.Add(messagePart); } if (isResponse) { SetReturnValue(message, operation); } } static void SetReturnValue(MessageDescription message, OperationDescription operation) { if (message.IsUntypedMessage) { message.Body.ReturnValue = message.Body.Parts[0]; message.Body.Parts.RemoveAt(0); } else if (!message.IsTypedMessage) { message.Body.ReturnValue = new MessagePartDescription(operation.Name + TypeLoader.ReturnSuffix, operation.DeclaringContract.Namespace); message.Body.ReturnValue.Type = TypeHelper.VoidType; } } public static void SetWrapperName(OperationDescription operation, bool isResponse, MessageDescription message) { message.Body.WrapperName = operation.Name + (isResponse ? TypeLoader.ResponseSuffix : string.Empty); message.Body.WrapperNamespace = operation.DeclaringContract.Namespace; } public static void ClearWrapperNames(OperationDescription operation) { // Reproduce logic from TypeLoader.CreateOperationDescription if (!operation.IsOneWay) { MessageDescription requestMessage = operation.Messages[0]; MessageDescription responseMessage = operation.Messages[1]; if (responseMessage.IsVoid && (requestMessage.IsUntypedMessage || requestMessage.IsTypedMessage)) { responseMessage.Body.WrapperName = null; responseMessage.Body.WrapperNamespace = null; } else if (requestMessage.IsVoid && (responseMessage.IsUntypedMessage || responseMessage.IsTypedMessage)) { requestMessage.Body.WrapperName = null; requestMessage.Body.WrapperNamespace = null; } } } public static FaultDescription CreateFaultDescription(OperationDescription operation, Type faultType, string overridingAction) { string name = NamingHelper.TypeName(faultType) + TypeLoader.FaultSuffix; string action = overridingAction ?? NamingHelper.GetMessageAction(operation, false) + name; FaultDescription result = new FaultDescription(action) { Namespace = operation.DeclaringContract.Namespace, DetailType = faultType }; result.SetNameOnly(new XmlName(name)); return result; } } }