internal SoapBindingUse Use;
internal HeaderInfo[] Headers;
+ internal HeaderInfo[] InHeaders;
+ internal HeaderInfo[] OutHeaders;
+ internal HeaderInfo[] FaultHeaders;
internal SoapExtensionRuntimeConfig[] SoapExtensions;
internal XmlMembersMapping InputMembersMapping;
internal XmlMembersMapping OutputMembersMapping;
+ internal XmlMembersMapping InputHeaderMembersMapping;
+ internal XmlMembersMapping OutputHeaderMembersMapping;
+ internal XmlMembersMapping FaultHeaderMembersMapping;
private int requestSerializerId;
private int responseSerializerId;
+ private int requestHeadersSerializerId = -1;
+ private int responseHeadersSerializerId = -1;
+ private int faultHeadersSerializerId = -1;
internal XmlSerializer RequestSerializer
{
{
get { return TypeStub.GetSerializer (responseSerializerId); }
}
+
+ internal XmlSerializer RequestHeadersSerializer
+ {
+ get { return requestHeadersSerializerId != -1 ? TypeStub.GetSerializer (requestHeadersSerializerId) : null; }
+ }
+
+ internal XmlSerializer ResponseHeadersSerializer
+ {
+ get { return responseHeadersSerializerId != -1 ? TypeStub.GetSerializer (responseHeadersSerializerId) : null; }
+ }
+
+ internal XmlSerializer FaultHeadersSerializer
+ {
+ get { return faultHeadersSerializerId != -1 ? TypeStub.GetSerializer (faultHeadersSerializerId) : null; }
+ }
+
//
// Constructor
Action = rma.Action;
Binding = rma.Binding;
- RequestName = rma.RequestElementName;
+
+ // When using RPC, MS.NET seems to ignore RequestElementName and
+ // MessageName, and it always uses the method name
+ RequestName = source.Name;
+ ResponseName = source.Name + "Response";
+// RequestName = rma.RequestElementName;
+// ResponseName = rma.ResponseElementName;
RequestNamespace = rma.RequestNamespace;
ResponseNamespace = rma.ResponseNamespace;
- ResponseName = rma.ResponseElementName;
ParameterStyle = SoapParameterStyle.Wrapped;
OneWay = rma.OneWay;
SoapBindingStyle = SoapBindingStyle.Rpc;
if (RequestName == "") RequestName = Name;
if (ResponseName == "") ResponseName = Name + "Response";
if (Action == null || Action == "")
- Action = RequestNamespace.EndsWith("/") ? (RequestNamespace + Name) : (RequestNamespace + "/" + Name);
+ Action = serviceNamespace.EndsWith("/") ? (serviceNamespace + Name) : (serviceNamespace + "/" + Name);
bool hasWrappingElem = (ParameterStyle == SoapParameterStyle.Wrapped);
bool writeAccessors = (SoapBindingStyle == SoapBindingStyle.Rpc);
responseSerializerId = parent.RegisterSerializer (OutputMembersMapping);
object[] o = source.GetCustomAttributes (typeof (SoapHeaderAttribute));
- Headers = new HeaderInfo[o.Length];
+ ArrayList allHeaderList = new ArrayList (o.Length);
+ ArrayList inHeaderList = new ArrayList (o.Length);
+ ArrayList outHeaderList = new ArrayList (o.Length);
+ ArrayList faultHeaderList = new ArrayList ();
+
+ SoapHeaderDirection unknownHeaderDirections = (SoapHeaderDirection)0;
+
for (int i = 0; i < o.Length; i++) {
SoapHeaderAttribute att = (SoapHeaderAttribute) o[i];
MemberInfo[] mems = source.DeclaringType.GetMember (att.MemberName);
if (mems.Length == 0) throw new InvalidOperationException ("Member " + att.MemberName + " not found in class " + source.DeclaringType.FullName + ".");
- Type headerType = (mems[0] is FieldInfo) ? ((FieldInfo)mems[0]).FieldType : ((PropertyInfo)mems[0]).PropertyType;
- Headers [i] = new HeaderInfo (mems[0], att);
- parent.RegisterHeaderType (headerType, serviceNamespace, Use);
+ HeaderInfo header = new HeaderInfo (mems[0], att);
+ allHeaderList.Add (header);
+ if (!header.IsUnknownHeader) {
+ if ((header.Direction & SoapHeaderDirection.In) != 0)
+ inHeaderList.Add (header);
+ if ((header.Direction & SoapHeaderDirection.Out) != 0)
+ outHeaderList.Add (header);
+ if ((header.Direction & SoapHeaderDirection.Fault) != 0)
+ faultHeaderList.Add (header);
+ } else
+ unknownHeaderDirections |= header.Direction;
}
+
+ Headers = (HeaderInfo[]) allHeaderList.ToArray (typeof(HeaderInfo));
+ if (inHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.In) != 0) {
+ InHeaders = (HeaderInfo[]) inHeaderList.ToArray (typeof(HeaderInfo));
+ XmlReflectionMember[] members = BuildHeadersReflectionMembers (InHeaders);
+
+ if (Use == SoapBindingUse.Literal)
+ InputHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
+ else
+ InputHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
+
+ requestHeadersSerializerId = parent.RegisterSerializer (InputHeaderMembersMapping);
+ }
+
+ if (outHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.Out) != 0) {
+ OutHeaders = (HeaderInfo[]) outHeaderList.ToArray (typeof(HeaderInfo));
+ XmlReflectionMember[] members = BuildHeadersReflectionMembers (OutHeaders);
+
+ if (Use == SoapBindingUse.Literal)
+ OutputHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
+ else
+ OutputHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
+
+ responseHeadersSerializerId = parent.RegisterSerializer (OutputHeaderMembersMapping);
+ }
+
+ if (faultHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.Fault) != 0) {
+ FaultHeaders = (HeaderInfo[]) faultHeaderList.ToArray (typeof(HeaderInfo));
+ XmlReflectionMember[] members = BuildHeadersReflectionMembers (FaultHeaders);
+
+ if (Use == SoapBindingUse.Literal)
+ FaultHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false);
+ else
+ FaultHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false);
+
+ faultHeadersSerializerId = parent.RegisterSerializer (FaultHeaderMembersMapping);
+ }
+
SoapExtensions = SoapExtension.GetMethodExtensions (source);
}
return out_members;
}
+ XmlReflectionMember [] BuildHeadersReflectionMembers (HeaderInfo[] headers)
+ {
+ XmlReflectionMember [] mems = new XmlReflectionMember [headers.Length];
+
+ for (int n=0; n<headers.Length; n++)
+ {
+ HeaderInfo header = headers [n];
+
+ XmlReflectionMember m = new XmlReflectionMember ();
+ m.IsReturnValue = false;
+ m.MemberName = header.HeaderType.Name;
+ m.MemberType = header.HeaderType;
+
+ // MS.NET reflects header classes in a weird way. The root element
+ // name is the CLR class name unless it is specified in an XmlRootAttribute.
+ // The usual is to use the xml type name by default, but not in this case.
+
+ XmlAttributes ats = new XmlAttributes (header.HeaderType);
+ if (ats.XmlRoot != null) {
+ XmlElementAttribute xe = new XmlElementAttribute ();
+ xe.ElementName = ats.XmlRoot.ElementName;
+ xe.Namespace = ats.XmlRoot.Namespace;
+ m.XmlAttributes = new XmlAttributes ();
+ m.XmlAttributes.XmlElements.Add (xe);
+ }
+
+ mems [n] = m;
+ }
+ return mems;
+ }
+
public HeaderInfo GetHeaderInfo (Type headerType)
{
foreach (HeaderInfo headerInfo in Headers)
if (headerInfo.HeaderType == headerType) return headerInfo;
return null;
}
+
+ public XmlSerializer GetBodySerializer (SoapHeaderDirection dir)
+ {
+ switch (dir) {
+ case SoapHeaderDirection.In: return RequestSerializer;
+ case SoapHeaderDirection.Out: return ResponseSerializer;
+ case SoapHeaderDirection.Fault: return Fault.Serializer;
+ default: return null;
+ }
+ }
+
+ public XmlSerializer GetHeaderSerializer (SoapHeaderDirection dir)
+ {
+ switch (dir) {
+ case SoapHeaderDirection.In: return RequestHeadersSerializer;
+ case SoapHeaderDirection.Out: return ResponseHeadersSerializer;
+ case SoapHeaderDirection.Fault: return FaultHeadersSerializer;
+ default: return null;
+ }
+ }
+
+ HeaderInfo[] GetHeaders (SoapHeaderDirection dir)
+ {
+ switch (dir) {
+ case SoapHeaderDirection.In: return InHeaders;
+ case SoapHeaderDirection.Out: return OutHeaders;
+ case SoapHeaderDirection.Fault: return FaultHeaders;
+ default: return null;
+ }
+ }
+
+ public object[] GetHeaderValueArray (SoapHeaderDirection dir, SoapHeaderCollection headers)
+ {
+ HeaderInfo[] headerInfos = GetHeaders (dir);
+ if (headerInfos == null) return null;
+
+ object[] hs = new object [headerInfos.Length];
+
+ for (int n=0; n<headers.Count; n++) {
+ SoapHeader h = headers[n];
+ Type t = h.GetType();
+ for (int i=0; i<headerInfos.Length; i++)
+ if (headerInfos [i].HeaderType == t)
+ hs [i] = h;
+ }
+ return hs;
+ }
}
internal class HeaderInfo
internal MemberInfo Member;
internal SoapHeaderAttribute AttributeInfo;
internal Type HeaderType;
+ internal bool IsUnknownHeader;
public HeaderInfo (MemberInfo member, SoapHeaderAttribute attributeInfo)
{
AttributeInfo = attributeInfo;
if (Member is PropertyInfo) HeaderType = ((PropertyInfo)Member).PropertyType;
else HeaderType = ((FieldInfo)Member).FieldType;
+
+ if (HeaderType == typeof(SoapHeader) || HeaderType == typeof(SoapUnknownHeader) ||
+ HeaderType == typeof(SoapHeader[]) || HeaderType == typeof(SoapUnknownHeader[]))
+ {
+ IsUnknownHeader = true;
+ }
+ else if (!typeof(SoapHeader).IsAssignableFrom (HeaderType))
+ throw new InvalidOperationException (string.Format ("Header members type must be a SoapHeader subclass"));
}
public object GetHeaderValue (object ob)
else return ((FieldInfo)Member).GetValue (ob);
}
- public void SetHeaderValue (object ob, object value)
+ public void SetHeaderValue (object ob, SoapHeader header)
{
+ object value = header;
+ if (IsUnknownHeader && HeaderType.IsArray)
+ {
+ SoapUnknownHeader uheader = header as SoapUnknownHeader;
+ SoapUnknownHeader[] array = (SoapUnknownHeader[]) GetHeaderValue (ob);
+ if (array == null || array.Length == 0) {
+ value = new SoapUnknownHeader[] { uheader };
+ }
+ else {
+ SoapUnknownHeader[] newArray = new SoapUnknownHeader [array.Length+1];
+ Array.Copy (array, newArray, array.Length);
+ newArray [array.Length] = uheader;
+ value = newArray;
+ }
+ }
+
if (Member is PropertyInfo) ((PropertyInfo)Member).SetValue (ob, value, null);
else ((FieldInfo)Member).SetValue (ob, value);
}
-
+
public SoapHeaderDirection Direction
{
get { return AttributeInfo.Direction; }
return res;
}
- internal void RegisterHeaderType (Type type, string serviceNamespace, SoapBindingUse use)
- {
- Hashtable serializers = header_serializers [(int)use];
- if (serializers == null) {
- serializers = new Hashtable ();
- header_serializers [(int)use] = serializers;
- header_serializers_byname [(int)use] = new Hashtable ();
- }
-
- if (serializers.ContainsKey (type))
- return;
-
- XmlTypeMapping tm;
- if (use == SoapBindingUse.Literal) {
- XmlReflectionImporter ri = new XmlReflectionImporter ();
-
- // MS.NET reflects header classes in a weird way. The root element
- // name is the CLR class name unless it is specified in an XmlRootAttribute.
- // The usual is to use the xml type name by default, but not in this case.
-
- XmlRootAttribute root;
- XmlAttributes ats = new XmlAttributes (type);
- if (ats.XmlRoot != null) root = ats.XmlRoot;
- else root = new XmlRootAttribute (type.Name);
-
- if (root.Namespace == null) root.Namespace = LogicalType.GetWebServiceLiteralNamespace (serviceNamespace);
- if (root.ElementName == null) root.ElementName = type.Name;
-
- tm = ri.ImportTypeMapping (type, root);
- }
- else {
- SoapReflectionImporter ri = new SoapReflectionImporter ();
- tm = ri.ImportTypeMapping (type, LogicalType.GetWebServiceEncodedNamespace (serviceNamespace));
- }
-
- int sid = RegisterSerializer (tm);
-
- serializers [type] = sid;
- header_serializers_byname [(int)use] [new XmlQualifiedName (tm.ElementName, tm.Namespace)] = sid;
- }
-
- internal XmlSerializer GetHeaderSerializer (Type type, SoapBindingUse use)
- {
- Hashtable table = header_serializers [(int)use];
- if (table == null) return null;
-
- return GetSerializer ((int) table [type]);
- }
-
- internal XmlSerializer GetHeaderSerializer (XmlQualifiedName qname, SoapBindingUse use)
- {
- Hashtable table = header_serializers_byname [(int)use];
- if (table == null) return null;
-
- return GetSerializer ((int) table [qname]);
- }
-
public SoapMethodStubInfo GetMethodForSoapAction (string name)
{
return (SoapMethodStubInfo) methods_byaction [name.Trim ('"',' ')];