2 // System.Web.Services.Description.HttpSimpleProtocolImporter.cs
5 // Lluis Sanchez Gual (lluis@ximian.com)
7 // Copyright (C) 2003 Ximian, Inc.
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Web.Services;
33 using System.Web.Services.Protocols;
34 using System.Web.Services.Configuration;
36 using System.Xml.Serialization;
37 using System.Configuration;
38 using System.Collections;
40 namespace System.Web.Services.Description
42 internal abstract class HttpSimpleProtocolImporter : ProtocolImporter
47 HttpBinding httpBinding;
49 SoapCodeExporter soapExporter;
50 SoapSchemaImporter soapImporter;
51 XmlCodeExporter xmlExporter;
52 XmlSchemaImporter xmlImporter;
53 CodeIdentifiers memberIds;
54 XmlReflectionImporter xmlReflectionImporter;
60 public HttpSimpleProtocolImporter ()
64 #endregion // Constructors
68 protected override CodeTypeDeclaration BeginClass ()
70 httpBinding = (HttpBinding) Binding.Extensions.Find (typeof(HttpBinding));
72 CodeTypeDeclaration codeClass = new CodeTypeDeclaration (ClassName);
74 string location = null;
75 HttpAddressBinding sab = (HttpAddressBinding) Port.Extensions.Find (typeof(HttpAddressBinding));
76 if (sab != null) location = sab.Location;
77 string url = GetServiceUrl (location);
79 CodeConstructor cc = new CodeConstructor ();
80 cc.Attributes = MemberAttributes.Public;
81 CodeExpression ce = new CodeFieldReferenceExpression (new CodeThisReferenceExpression(), "Url");
82 CodeAssignStatement cas = new CodeAssignStatement (ce, new CodePrimitiveExpression (url));
83 cc.Statements.Add (cas);
84 codeClass.Members.Add (cc);
86 memberIds = new CodeIdentifiers ();
90 protected override void BeginNamespace ()
92 xmlImporter = new XmlSchemaImporter (LiteralSchemas, ClassNames);
93 soapImporter = new SoapSchemaImporter (EncodedSchemas, ClassNames);
94 xmlExporter = new XmlCodeExporter (CodeNamespace, null);
95 xmlReflectionImporter = new XmlReflectionImporter ();
98 protected override void EndClass ()
100 if (xmlExporter.IncludeMetadata.Count > 0)
102 if (CodeTypeDeclaration.CustomAttributes == null)
103 CodeTypeDeclaration.CustomAttributes = new CodeAttributeDeclarationCollection ();
104 CodeTypeDeclaration.CustomAttributes.AddRange (xmlExporter.IncludeMetadata);
108 protected override void EndNamespace ()
112 protected override bool IsBindingSupported ()
114 throw new NotImplementedException ();
118 protected override bool IsOperationFlowSupported (OperationFlow flow)
120 throw new NotImplementedException ();
123 protected override CodeMemberMethod GenerateMethod ()
127 HttpOperationBinding httpOper = OperationBinding.Extensions.Find (typeof (HttpOperationBinding)) as HttpOperationBinding;
128 if (httpOper == null) throw new Exception ("Http operation binding not found");
130 XmlMembersMapping inputMembers = ImportInMembersMapping (InputMessage);
131 XmlTypeMapping outputMember = ImportOutMembersMapping (OutputMessage);
133 CodeMemberMethod met = GenerateMethod (memberIds, httpOper, inputMembers, outputMember);
135 xmlExporter.ExportMembersMapping (inputMembers);
136 if (outputMember != null)
137 xmlExporter.ExportTypeMapping (outputMember);
143 UnsupportedOperationBindingWarning (ex.Message);
148 XmlMembersMapping ImportInMembersMapping (Message msg)
150 SoapSchemaMember[] mems = new SoapSchemaMember [msg.Parts.Count];
151 for (int n=0; n<mems.Length; n++)
153 SoapSchemaMember mem = new SoapSchemaMember();
154 mem.MemberName = msg.Parts[n].Name;
155 mem.MemberType = msg.Parts[n].Type;
158 return soapImporter.ImportMembersMapping (Operation.Name, "", mems);
161 XmlTypeMapping ImportOutMembersMapping (Message msg)
163 if (msg.Parts.Count == 0) return null;
165 if (msg.Parts[0].Name == "Body" && msg.Parts[0].Element == XmlQualifiedName.Empty)
166 return xmlReflectionImporter.ImportTypeMapping (typeof(XmlNode));
168 return xmlImporter.ImportTypeMapping (msg.Parts[0].Element);
171 CodeMemberMethod GenerateMethod (CodeIdentifiers memberIds, HttpOperationBinding httpOper, XmlMembersMapping inputMembers, XmlTypeMapping outputMember)
173 CodeIdentifiers pids = new CodeIdentifiers ();
174 CodeMemberMethod method = new CodeMemberMethod ();
175 CodeMemberMethod methodBegin = new CodeMemberMethod ();
176 CodeMemberMethod methodEnd = new CodeMemberMethod ();
177 method.Attributes = MemberAttributes.Public;
178 methodBegin.Attributes = MemberAttributes.Public;
179 methodEnd.Attributes = MemberAttributes.Public;
181 // Find unique names for temporary variables
183 for (int n=0; n<inputMembers.Count; n++)
184 pids.AddUnique (inputMembers[n].MemberName, inputMembers[n]);
186 string varAsyncResult = pids.AddUnique ("asyncResult","asyncResult");
187 string varResults = pids.AddUnique ("results","results");
188 string varCallback = pids.AddUnique ("callback","callback");
189 string varAsyncState = pids.AddUnique ("asyncState","asyncState");
191 string messageName = memberIds.AddUnique(CodeIdentifier.MakeValid(Operation.Name),method);
193 method.Name = Operation.Name;
194 methodBegin.Name = memberIds.AddUnique(CodeIdentifier.MakeValid("Begin" + Operation.Name),method);
195 methodEnd.Name = memberIds.AddUnique(CodeIdentifier.MakeValid("End" + Operation.Name),method);
197 method.ReturnType = new CodeTypeReference (typeof(void));
198 methodEnd.ReturnType = new CodeTypeReference (typeof(void));
199 methodEnd.Parameters.Add (new CodeParameterDeclarationExpression (typeof (IAsyncResult),varAsyncResult));
201 CodeExpression[] paramArray = new CodeExpression [inputMembers.Count];
203 for (int n=0; n<inputMembers.Count; n++)
205 string ptype = GetSimpleType (inputMembers[n]);
206 CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression (ptype, inputMembers[n].MemberName);
208 param.Direction = FieldDirection.In;
209 method.Parameters.Add (param);
210 methodBegin.Parameters.Add (param);
211 paramArray [n] = new CodeVariableReferenceExpression (param.Name);
215 if (outputMember != null)
217 method.ReturnType = new CodeTypeReference (outputMember.TypeFullName);
218 methodEnd.ReturnType = new CodeTypeReference (outputMember.TypeFullName);
219 xmlExporter.AddMappingMetadata (method.ReturnTypeCustomAttributes, outputMember, "");
223 methodBegin.Parameters.Add (new CodeParameterDeclarationExpression (typeof (AsyncCallback),varCallback));
224 methodBegin.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object),varAsyncState));
225 methodBegin.ReturnType = new CodeTypeReference (typeof(IAsyncResult));
227 // Array of input parameters
229 CodeArrayCreateExpression methodParams;
230 if (paramArray.Length > 0)
231 methodParams = new CodeArrayCreateExpression (typeof(object), paramArray);
233 methodParams = new CodeArrayCreateExpression (typeof(object), 0);
235 // Generate method url
237 CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
239 CodeExpression thisURlExp = new CodeFieldReferenceExpression (ethis, "Url");
240 CodePrimitiveExpression metUrl = new CodePrimitiveExpression (httpOper.Location);
241 CodeBinaryOperatorExpression expMethodLocation = new CodeBinaryOperatorExpression (thisURlExp, CodeBinaryOperatorType.Add, metUrl);
245 CodePrimitiveExpression varMsgName = new CodePrimitiveExpression (messageName);
246 CodeMethodInvokeExpression inv;
248 inv = new CodeMethodInvokeExpression (ethis, "Invoke", varMsgName, expMethodLocation, methodParams);
250 method.Statements.Add (new CodeMethodReturnStatement (new CodeCastExpression (method.ReturnType, inv)));
252 method.Statements.Add (inv);
256 CodeExpression expCallb = new CodeVariableReferenceExpression (varCallback);
257 CodeExpression expAsyncs = new CodeVariableReferenceExpression (varAsyncState);
258 inv = new CodeMethodInvokeExpression (ethis, "BeginInvoke", varMsgName, expMethodLocation, methodParams, expCallb, expAsyncs);
259 methodBegin.Statements.Add (new CodeMethodReturnStatement (inv));
263 CodeExpression varAsyncr = new CodeVariableReferenceExpression (varAsyncResult);
264 inv = new CodeMethodInvokeExpression (ethis, "EndInvoke", varAsyncr);
266 methodEnd.Statements.Add (new CodeMethodReturnStatement (new CodeCastExpression (methodEnd.ReturnType, inv)));
268 methodEnd.Statements.Add (inv);
272 CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Web.Services.Protocols.HttpMethodAttribute");
273 att.Arguments.Add (new CodeAttributeArgument (new CodeTypeOfExpression(GetOutMimeFormatter ())));
274 att.Arguments.Add (new CodeAttributeArgument (new CodeTypeOfExpression(GetInMimeFormatter ())));
275 AddCustomAttribute (method, att, true);
277 CodeTypeDeclaration.Members.Add (method);
278 CodeTypeDeclaration.Members.Add (methodBegin);
279 CodeTypeDeclaration.Members.Add (methodEnd);
284 protected virtual Type GetInMimeFormatter ()
289 protected virtual Type GetOutMimeFormatter ()
291 if (OperationBinding.Output.Extensions.Find (typeof(MimeXmlBinding)) != null)
292 return typeof (XmlReturnReader);
294 MimeContentBinding bin = (MimeContentBinding) OperationBinding.Output.Extensions.Find (typeof(MimeContentBinding));
295 if (bin != null && bin.Type == "text/xml")
296 return typeof (XmlReturnReader);
298 return typeof(NopReturnReader);
301 string GetSimpleType (XmlMemberMapping member)
303 // MS seems to always use System.String for input parameters, except for byte[]
305 switch (member.TypeName)
309 return "System.String";
312 string ptype = member.TypeFullName;
313 int i = ptype.IndexOf ('[');
315 return "System.String";
317 return "System.String" + ptype.Substring (i);