2 // System.Web.Services.Description.ProtocolImporter.cs
5 // Tim Coleman (tim@timcoleman.com)
6 // Lluis Sanchez Gual (lluis@ximian.com)
8 // Copyright (C) Tim Coleman, 2002
13 using System.Web.Services;
14 using System.Web.Services.Protocols;
15 using System.Xml.Serialization;
17 using System.Xml.Schema;
18 using System.Collections;
19 using System.Configuration;
21 namespace System.Web.Services.Description {
22 public abstract class ProtocolImporter {
28 CodeIdentifiers classNames;
29 CodeNamespace codeNamespace;
30 CodeCompileUnit codeCompileUnit;
31 CodeTypeDeclaration codeTypeDeclaration;
35 OperationBinding operationBinding;
36 Message outputMessage;
41 ServiceDescriptionImportWarnings warnings = (ServiceDescriptionImportWarnings)0;
42 ServiceDescriptionImporter descriptionImporter;
44 XmlSchemas xmlSchemas;
45 XmlSchemas soapSchemas;
51 protected ProtocolImporter ()
55 #endregion // Constructors
60 public XmlSchemas AbstractSchemas {
61 get { return descriptionImporter.Schemas; }
64 public Binding Binding {
65 get { return binding; }
68 public string ClassName {
69 get { return className; }
72 public CodeIdentifiers ClassNames {
73 get { return classNames; }
76 public CodeNamespace CodeNamespace {
77 get { return codeNamespace; }
80 public CodeTypeDeclaration CodeTypeDeclaration {
81 get { return codeTypeDeclaration; }
85 public XmlSchemas ConcreteSchemas {
86 get { return descriptionImporter.Schemas; }
89 public Message InputMessage {
90 get { return inputMessage; }
93 public string MethodName {
94 get { return methodName; }
97 public Operation Operation {
98 get { return operation; }
101 public OperationBinding OperationBinding {
102 get { return operationBinding; }
105 public Message OutputMessage {
106 get { return outputMessage; }
113 public PortType PortType {
114 get { return portType; }
117 public abstract string ProtocolName {
121 public XmlSchemas Schemas {
122 get { return descriptionImporter.Schemas; }
125 public Service Service {
126 get { return service; }
129 public ServiceDescriptionCollection ServiceDescriptions {
130 get { return descriptionImporter.ServiceDescriptions; }
133 public ServiceDescriptionImportStyle Style {
134 get { return descriptionImporter.Style; }
137 public ServiceDescriptionImportWarnings Warnings {
138 get { return warnings; }
139 set { warnings = value; }
142 internal ImportInfo ImportInfo
144 get { return iinfo; }
147 internal XmlSchemas LiteralSchemas
149 get { return xmlSchemas; }
152 internal XmlSchemas EncodedSchemas
154 get { return soapSchemas; }
157 #endregion // Properties
161 internal bool Import (ServiceDescriptionImporter descriptionImporter, CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, ArrayList importInfo)
163 this.descriptionImporter = descriptionImporter;
164 this.classNames = new CodeIdentifiers();;
165 this.codeNamespace = codeNamespace;
166 this.codeCompileUnit = codeCompileUnit;
168 warnings = (ServiceDescriptionImportWarnings) 0;
172 ClasifySchemas (importInfo);
176 foreach (ImportInfo info in importInfo)
178 foreach (Service service in info.ServiceDescription.Services)
180 this.service = service;
181 int bindingCount = 0;
182 foreach (Port port in service.Ports)
184 binding = ServiceDescriptions.GetBinding (port.Binding);
185 if (IsBindingSupported ()) bindingCount ++;
188 foreach (Port port in service.Ports)
192 binding = ServiceDescriptions.GetBinding (port.Binding);
193 if (!IsBindingSupported ()) continue;
196 ImportPortBinding (bindingCount > 1);
203 if (!found) warnings = ServiceDescriptionImportWarnings.NoCodeGenerated;
207 void ImportPortBinding (bool multipleBindings)
209 if (multipleBindings) className = port.Name;
210 else className = service.Name;
212 className = classNames.AddUnique (CodeIdentifier.MakeValid (className), port);
213 className = className.Replace ("_x0020_", ""); // MS.NET seems to do this
217 portType = ServiceDescriptions.GetPortType (binding.Type);
218 if (portType == null) throw new Exception ("Port type not found: " + binding.Type);
220 CodeTypeDeclaration codeClass = BeginClass ();
221 codeTypeDeclaration = codeClass;
222 AddCodeType (codeClass, port.Documentation);
223 codeClass.Attributes = MemberAttributes.Public;
225 if (service.Documentation != null && service.Documentation != "")
226 AddComments (codeClass, service.Documentation);
228 CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Diagnostics.DebuggerStepThroughAttribute");
229 AddCustomAttribute (codeClass, att, true);
231 att = new CodeAttributeDeclaration ("System.ComponentModel.DesignerCategoryAttribute");
232 att.Arguments.Add (GetArg ("code"));
233 AddCustomAttribute (codeClass, att, true);
235 if (binding.Operations.Count == 0) {
236 warnings |= ServiceDescriptionImportWarnings.NoMethodsGenerated;
240 foreach (OperationBinding oper in binding.Operations)
242 operationBinding = oper;
243 operation = FindPortOperation ();
244 if (operation == null) throw new Exception ("Operation " + operationBinding.Name + " not found in portType " + PortType.Name);
246 foreach (OperationMessage omsg in operation.Messages)
248 Message msg = ServiceDescriptions.GetMessage (omsg.Message);
249 if (msg == null) throw new Exception ("Message not found: " + omsg.Message);
251 if (omsg is OperationInput)
257 CodeMemberMethod method = GenerateMethod ();
261 methodName = method.Name;
262 if (operation.Documentation != null && operation.Documentation != "")
263 AddComments (method, operation.Documentation);
269 catch (InvalidOperationException ex)
271 warnings |= ServiceDescriptionImportWarnings.NoCodeGenerated;
272 UnsupportedBindingWarning (ex.Message);
276 Operation FindPortOperation ()
278 string inMessage = null;
279 string outMessage = null;
282 if (operationBinding.Input == null) throw new InvalidOperationException ("Input operation binding not found");
283 inMessage = (operationBinding.Input.Name != null) ? operationBinding.Input.Name : operationBinding.Name;
285 if (operationBinding.Output != null) {
286 outMessage = (operationBinding.Output.Name != null) ? operationBinding.Output.Name : operationBinding.Name;
290 string operName = operationBinding.Name;
292 Operation foundOper = null;
293 foreach (Operation oper in PortType.Operations)
295 if (oper.Name == operName)
298 foreach (OperationMessage omsg in oper.Messages)
300 if (omsg is OperationInput && GetOperMessageName (omsg, operName) == inMessage) hits++;
301 if (omsg is OperationOutput && GetOperMessageName (omsg, operName) == outMessage) hits++;
303 if (hits == numMsg) return oper;
310 string GetOperMessageName (OperationMessage msg, string operName)
312 if (msg.Name == null) return operName;
313 else return msg.Name;
316 internal string GetServiceUrl (string location)
318 if (ImportInfo.AppSettingUrlKey == null || ImportInfo.AppSettingUrlKey == string.Empty)
323 if (Style == ServiceDescriptionImportStyle.Server) throw new InvalidOperationException ("Cannot set appSettingUrlKey if Style is Server");
324 url = ConfigurationSettings.AppSettings [ImportInfo.AppSettingUrlKey];
325 if (ImportInfo.AppSettingBaseUrl != null && ImportInfo.AppSettingBaseUrl != string.Empty)
326 url += "/" + ImportInfo.AppSettingBaseUrl + "/" + location;
331 void ClasifySchemas (ArrayList importInfo)
333 // I don't like this, but I could not find any other way of clasifying
334 // schemas between encoded and literal.
336 xmlSchemas = new XmlSchemas ();
337 soapSchemas = new XmlSchemas ();
339 foreach (ImportInfo info in importInfo)
341 foreach (Service service in info.ServiceDescription.Services)
343 foreach (Port port in service.Ports)
347 binding = ServiceDescriptions.GetBinding (port.Binding);
348 if (binding == null) continue;
349 portType = ServiceDescriptions.GetPortType (binding.Type);
350 if (portType == null) continue;
352 foreach (OperationBinding oper in binding.Operations)
354 operationBinding = oper;
355 operation = FindPortOperation ();
356 if (operation == null) continue;
358 foreach (OperationMessage omsg in operation.Messages)
360 Message msg = ServiceDescriptions.GetMessage (omsg.Message);
361 if (msg == null) continue;
363 if (omsg is OperationInput)
369 if (GetMessageEncoding (oper.Input) == SoapBindingUse.Encoded)
370 AddMessageSchema (soapSchemas, oper.Input, inputMessage);
372 AddMessageSchema (xmlSchemas, oper.Input, inputMessage);
374 if (oper.Output != null) {
375 if (GetMessageEncoding (oper.Output) == SoapBindingUse.Encoded)
376 AddMessageSchema (soapSchemas, oper.Output, outputMessage);
378 AddMessageSchema (xmlSchemas, oper.Output, outputMessage);
385 XmlSchemas defaultList = xmlSchemas;
387 if (xmlSchemas.Count == 0 && soapSchemas.Count > 0)
388 defaultList = soapSchemas;
390 // Schemas not referenced by any message
391 foreach (XmlSchema sc in Schemas)
393 if (!soapSchemas.Contains (sc) && !xmlSchemas.Contains (sc)) {
394 if (ImportsEncodedNamespace (sc))
395 soapSchemas.Add (sc);
397 defaultList.Add (sc);
402 void AddMessageSchema (XmlSchemas schemas, MessageBinding mb, Message msg)
404 foreach (MessagePart part in msg.Parts)
406 if (part.Element != XmlQualifiedName.Empty)
407 AddIncludingSchema (schemas, part.Element.Namespace);
408 else if (part.Type != XmlQualifiedName.Empty)
409 AddIncludingSchema (schemas, part.Type.Namespace);
411 SoapBodyBinding sbb = mb.Extensions.Find (typeof(SoapBodyBinding)) as SoapBodyBinding;
412 if (sbb != null) AddIncludingSchema (schemas, sbb.Namespace);
415 void AddIncludingSchema (XmlSchemas list, string ns)
417 XmlSchema sc = Schemas [ns];
418 if (sc == null || list.Contains (sc)) return;
420 foreach (XmlSchemaObject ob in sc.Includes)
422 XmlSchemaImport import = ob as XmlSchemaImport;
423 if (import != null) AddIncludingSchema (list, import.Namespace);
427 SoapBindingUse GetMessageEncoding (MessageBinding mb)
429 SoapBodyBinding sbb = mb.Extensions.Find (typeof(SoapBodyBinding)) as SoapBodyBinding;
432 if (mb is InputBinding) return SoapBindingUse.Encoded;
433 else return SoapBindingUse.Literal;
436 if (sbb.Use == SoapBindingUse.Encoded) return SoapBindingUse.Encoded;
438 return SoapBindingUse.Literal;
441 bool ImportsEncodedNamespace (XmlSchema sc)
443 foreach (XmlSchemaObject ob in sc.Includes)
445 XmlSchemaImport import = ob as XmlSchemaImport;
446 if (import.Namespace == SoapProtocolReflector.EncodingNamespace) return true;
452 public void AddExtensionWarningComments (CodeCommentStatementCollection comments, ServiceDescriptionFormatExtensionCollection extensions)
454 throw new NotImplementedException ();
457 protected abstract CodeTypeDeclaration BeginClass ();
459 protected virtual void BeginNamespace ()
463 protected virtual void EndClass ()
467 protected virtual void EndNamespace ()
471 protected abstract CodeMemberMethod GenerateMethod ();
472 protected abstract bool IsBindingSupported ();
473 protected abstract bool IsOperationFlowSupported (OperationFlow flow);
476 public Exception OperationBindingSyntaxException (string text)
478 throw new NotImplementedException ();
482 public Exception OperationSyntaxException (string text)
484 throw new NotImplementedException ();
487 public void UnsupportedBindingWarning (string text)
489 warnings |= ServiceDescriptionImportWarnings.UnsupportedBindingsIgnored;
490 AddGlobalComments ("WARNING: Could not generate proxy for binding " + binding.Name + ". " + text);
493 public void UnsupportedOperationBindingWarning (string text)
495 warnings |= ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored;
496 AddGlobalComments ("WARNING: Could not generate operation " + OperationBinding.Name + ". " + text);
499 public void UnsupportedOperationWarning (string text)
501 warnings |= ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored;
502 AddGlobalComments ("WARNING: Could not generate operation " + OperationBinding.Name + ". " + text);
505 void AddGlobalComments (string comments)
507 codeNamespace.Comments.Add (new CodeCommentStatement (comments, false));
510 void AddComments (CodeTypeMember member, string comments)
512 if (comments == null || comments == "") member.Comments.Add (new CodeCommentStatement ("<remarks/>", true));
513 else member.Comments.Add (new CodeCommentStatement ("<remarks>\n" + comments + "\n</remarks>", true));
516 void AddCodeType (CodeTypeDeclaration type, string comments)
518 AddComments (type, comments);
519 codeNamespace.Types.Add (type);
522 internal void AddCustomAttribute (CodeTypeMember ctm, CodeAttributeDeclaration att, bool addIfNoParams)
524 if (att.Arguments.Count == 0 && !addIfNoParams) return;
526 if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
527 ctm.CustomAttributes.Add (att);
530 internal void AddCustomAttribute (CodeTypeMember ctm, string name, params CodeAttributeArgument[] args)
532 if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
533 ctm.CustomAttributes.Add (new CodeAttributeDeclaration (name, args));
536 internal CodeAttributeArgument GetArg (string name, object value)
538 return new CodeAttributeArgument (name, new CodePrimitiveExpression(value));
541 internal CodeAttributeArgument GetEnumArg (string name, string enumType, string enumValue)
543 return new CodeAttributeArgument (name, new CodeFieldReferenceExpression (new CodeTypeReferenceExpression(enumType), enumValue));
546 internal CodeAttributeArgument GetArg (object value)
548 return new CodeAttributeArgument (new CodePrimitiveExpression(value));
551 internal CodeAttributeArgument GetTypeArg (string name, string typeName)
553 return new CodeAttributeArgument (name, new CodeTypeOfExpression(typeName));