275 lines
11 KiB
C#
275 lines
11 KiB
C#
|
//----------------------------------------------------------------
|
||
|
// 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;
|
||
|
}
|
||
|
}
|
||
|
}
|