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;
76 HttpAddressBinding sab
= (HttpAddressBinding
) Port
.Extensions
.Find (typeof(HttpAddressBinding
));
77 if (sab
!= null) location
= sab
.Location
;
80 CodeConstructor cc
= new CodeConstructor ();
81 cc
.Attributes
= MemberAttributes
.Public
;
82 GenerateServiceUrl (location
, cc
.Statements
);
83 codeClass
.Members
.Add (cc
);
85 memberIds
= new CodeIdentifiers ();
89 protected override void BeginNamespace ()
91 xmlImporter
= new XmlSchemaImporter (LiteralSchemas
, ClassNames
);
92 soapImporter
= new SoapSchemaImporter (EncodedSchemas
, ClassNames
);
93 xmlExporter
= new XmlCodeExporter (CodeNamespace
, null);
94 xmlReflectionImporter
= new XmlReflectionImporter ();
97 protected override void EndClass ()
99 if (xmlExporter
.IncludeMetadata
.Count
> 0)
101 if (CodeTypeDeclaration
.CustomAttributes
== null)
102 CodeTypeDeclaration
.CustomAttributes
= new CodeAttributeDeclarationCollection ();
103 CodeTypeDeclaration
.CustomAttributes
.AddRange (xmlExporter
.IncludeMetadata
);
107 protected override void EndNamespace ()
111 protected override bool IsBindingSupported ()
113 throw new NotImplementedException ();
117 protected override bool IsOperationFlowSupported (OperationFlow flow
)
119 throw new NotImplementedException ();
122 protected override CodeMemberMethod
GenerateMethod ()
126 HttpOperationBinding httpOper
= OperationBinding
.Extensions
.Find (typeof (HttpOperationBinding
)) as HttpOperationBinding
;
127 if (httpOper
== null) throw new Exception ("Http operation binding not found");
129 XmlMembersMapping inputMembers
= ImportInMembersMapping (InputMessage
);
130 XmlTypeMapping outputMember
= ImportOutMembersMapping (OutputMessage
);
132 CodeMemberMethod met
= GenerateMethod (memberIds
, httpOper
, inputMembers
, outputMember
);
134 xmlExporter
.ExportMembersMapping (inputMembers
);
135 if (outputMember
!= null)
136 xmlExporter
.ExportTypeMapping (outputMember
);
142 UnsupportedOperationBindingWarning (ex
.Message
);
147 XmlMembersMapping
ImportInMembersMapping (Message msg
)
149 SoapSchemaMember
[] mems
= new SoapSchemaMember
[msg
.Parts
.Count
];
150 for (int n
=0; n
<mems
.Length
; n
++)
152 SoapSchemaMember mem
= new SoapSchemaMember();
153 mem
.MemberName
= msg
.Parts
[n
].Name
;
154 mem
.MemberType
= msg
.Parts
[n
].Type
;
157 return soapImporter
.ImportMembersMapping (Operation
.Name
, "", mems
);
160 XmlTypeMapping
ImportOutMembersMapping (Message msg
)
162 if (msg
.Parts
.Count
== 0) return null;
164 if (msg
.Parts
[0].Name
== "Body" && msg
.Parts
[0].Element
== XmlQualifiedName
.Empty
)
165 return xmlReflectionImporter
.ImportTypeMapping (typeof(XmlNode
));
167 // This is a bit hacky. The issue is that types such as string[] are to be imported
168 // as such, not as ArrayOfString class. ImportTypeMapping will return a
169 // class if the type has not been imported as an array before, hence the
170 // call to ImportMembersMapping.
171 xmlImporter
.ImportMembersMapping (new XmlQualifiedName
[] {msg.Parts[0].Element}
);
172 return xmlImporter
.ImportTypeMapping (msg
.Parts
[0].Element
);
176 CodeMemberMethod
GenerateMethod (CodeIdentifiers memberIds
, HttpOperationBinding httpOper
, XmlMembersMapping inputMembers
, XmlTypeMapping outputMember
)
178 CodeIdentifiers pids
= new CodeIdentifiers ();
179 CodeMemberMethod method
= new CodeMemberMethod ();
180 CodeMemberMethod methodBegin
= new CodeMemberMethod ();
181 CodeMemberMethod methodEnd
= new CodeMemberMethod ();
182 method
.Attributes
= MemberAttributes
.Public
;
183 methodBegin
.Attributes
= MemberAttributes
.Public
;
184 methodEnd
.Attributes
= MemberAttributes
.Public
;
186 // Find unique names for temporary variables
188 for (int n
=0; n
<inputMembers
.Count
; n
++)
189 pids
.AddUnique (inputMembers
[n
].MemberName
, inputMembers
[n
]);
191 string varAsyncResult
= pids
.AddUnique ("asyncResult","asyncResult");
192 string varResults
= pids
.AddUnique ("results","results");
193 string varCallback
= pids
.AddUnique ("callback","callback");
194 string varAsyncState
= pids
.AddUnique ("asyncState","asyncState");
196 string messageName
= memberIds
.AddUnique(CodeIdentifier
.MakeValid(Operation
.Name
),method
);
198 method
.Name
= Operation
.Name
;
199 methodBegin
.Name
= memberIds
.AddUnique(CodeIdentifier
.MakeValid("Begin" + Operation
.Name
),method
);
200 methodEnd
.Name
= memberIds
.AddUnique(CodeIdentifier
.MakeValid("End" + Operation
.Name
),method
);
202 method
.ReturnType
= new CodeTypeReference (typeof(void));
203 methodEnd
.ReturnType
= new CodeTypeReference (typeof(void));
204 methodEnd
.Parameters
.Add (new CodeParameterDeclarationExpression (typeof (IAsyncResult
),varAsyncResult
));
206 CodeExpression
[] paramArray
= new CodeExpression
[inputMembers
.Count
];
208 for (int n
=0; n
<inputMembers
.Count
; n
++)
210 string ptype
= GetSimpleType (inputMembers
[n
]);
211 CodeParameterDeclarationExpression param
= new CodeParameterDeclarationExpression (ptype
, inputMembers
[n
].MemberName
);
213 param
.Direction
= FieldDirection
.In
;
214 method
.Parameters
.Add (param
);
215 methodBegin
.Parameters
.Add (param
);
216 paramArray
[n
] = new CodeVariableReferenceExpression (param
.Name
);
220 if (outputMember
!= null)
222 method
.ReturnType
= new CodeTypeReference (outputMember
.TypeFullName
);
223 methodEnd
.ReturnType
= new CodeTypeReference (outputMember
.TypeFullName
);
224 xmlExporter
.AddMappingMetadata (method
.ReturnTypeCustomAttributes
, outputMember
, "");
228 methodBegin
.Parameters
.Add (new CodeParameterDeclarationExpression (typeof (AsyncCallback
),varCallback
));
229 methodBegin
.Parameters
.Add (new CodeParameterDeclarationExpression (typeof (object),varAsyncState
));
230 methodBegin
.ReturnType
= new CodeTypeReference (typeof(IAsyncResult
));
232 // Array of input parameters
234 CodeArrayCreateExpression methodParams
;
235 if (paramArray
.Length
> 0)
236 methodParams
= new CodeArrayCreateExpression (typeof(object), paramArray
);
238 methodParams
= new CodeArrayCreateExpression (typeof(object), 0);
240 // Generate method url
242 CodeThisReferenceExpression ethis
= new CodeThisReferenceExpression();
244 CodeExpression thisURlExp
= new CodeFieldReferenceExpression (ethis
, "Url");
245 CodePrimitiveExpression metUrl
= new CodePrimitiveExpression (httpOper
.Location
);
246 CodeBinaryOperatorExpression expMethodLocation
= new CodeBinaryOperatorExpression (thisURlExp
, CodeBinaryOperatorType
.Add
, metUrl
);
250 CodePrimitiveExpression varMsgName
= new CodePrimitiveExpression (messageName
);
251 CodeMethodInvokeExpression inv
;
253 inv
= new CodeMethodInvokeExpression (ethis
, "Invoke", varMsgName
, expMethodLocation
, methodParams
);
255 method
.Statements
.Add (new CodeMethodReturnStatement (new CodeCastExpression (method
.ReturnType
, inv
)));
257 method
.Statements
.Add (inv
);
261 CodeExpression expCallb
= new CodeVariableReferenceExpression (varCallback
);
262 CodeExpression expAsyncs
= new CodeVariableReferenceExpression (varAsyncState
);
263 inv
= new CodeMethodInvokeExpression (ethis
, "BeginInvoke", varMsgName
, expMethodLocation
, methodParams
, expCallb
, expAsyncs
);
264 methodBegin
.Statements
.Add (new CodeMethodReturnStatement (inv
));
268 CodeExpression varAsyncr
= new CodeVariableReferenceExpression (varAsyncResult
);
269 inv
= new CodeMethodInvokeExpression (ethis
, "EndInvoke", varAsyncr
);
271 methodEnd
.Statements
.Add (new CodeMethodReturnStatement (new CodeCastExpression (methodEnd
.ReturnType
, inv
)));
273 methodEnd
.Statements
.Add (inv
);
277 CodeAttributeDeclaration att
= new CodeAttributeDeclaration ("System.Web.Services.Protocols.HttpMethodAttribute");
278 att
.Arguments
.Add (new CodeAttributeArgument (new CodeTypeOfExpression(GetOutMimeFormatter ())));
279 att
.Arguments
.Add (new CodeAttributeArgument (new CodeTypeOfExpression(GetInMimeFormatter ())));
280 AddCustomAttribute (method
, att
, true);
282 CodeTypeDeclaration
.Members
.Add (method
);
283 CodeTypeDeclaration
.Members
.Add (methodBegin
);
284 CodeTypeDeclaration
.Members
.Add (methodEnd
);
290 internal override CodeExpression
BuildInvokeAsync (string messageName
, CodeArrayCreateExpression paramsArray
, CodeExpression delegateField
, CodeExpression userStateVar
)
292 HttpOperationBinding httpOper
= OperationBinding
.Extensions
.Find (typeof (HttpOperationBinding
)) as HttpOperationBinding
;
294 CodeThisReferenceExpression ethis
= new CodeThisReferenceExpression();
296 CodeExpression thisURlExp
= new CodeFieldReferenceExpression (ethis
, "Url");
297 CodePrimitiveExpression metUrl
= new CodePrimitiveExpression (httpOper
.Location
);
298 CodeBinaryOperatorExpression expMethodLocation
= new CodeBinaryOperatorExpression (thisURlExp
, CodeBinaryOperatorType
.Add
, metUrl
);
300 CodeMethodInvokeExpression inv2
= new CodeMethodInvokeExpression (ethis
, "InvokeAsync");
301 inv2
.Parameters
.Add (new CodePrimitiveExpression (messageName
));
302 inv2
.Parameters
.Add (expMethodLocation
);
303 inv2
.Parameters
.Add (paramsArray
);
304 inv2
.Parameters
.Add (delegateField
);
305 inv2
.Parameters
.Add (userStateVar
);
310 protected virtual Type
GetInMimeFormatter ()
315 protected virtual Type
GetOutMimeFormatter ()
317 if (OperationBinding
.Output
.Extensions
.Find (typeof(MimeXmlBinding
)) != null)
318 return typeof (XmlReturnReader
);
320 MimeContentBinding bin
= (MimeContentBinding
) OperationBinding
.Output
.Extensions
.Find (typeof(MimeContentBinding
));
321 if (bin
!= null && bin
.Type
== "text/xml")
322 return typeof (XmlReturnReader
);
324 return typeof(NopReturnReader
);
327 string GetSimpleType (XmlMemberMapping member
)
329 // MS seems to always use System.String for input parameters, except for byte[]
331 switch (member
.TypeName
)
335 return "System.String";
338 string ptype
= member
.TypeFullName
;
339 int i
= ptype
.IndexOf ('[');
341 return "System.String";
343 return "System.String" + ptype
.Substring (i
);