// Copyright (C) Tim Coleman, 2002
//
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
using System;
using System.CodeDom;
+using System.CodeDom.Compiler;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Serialization;
ImportInfo iinfo;
XmlSchemas xmlSchemas;
XmlSchemas soapSchemas;
+
+#if NET_2_0
+ ArrayList asyncTypes = new ArrayList ();
+#endif
#endregion // Fields
{
get { return soapSchemas; }
}
+
+#if NET_2_0
+ internal CodeGenerationOptions CodeGenerationOptions {
+ get { return descriptionImporter.CodeGenerationOptions; }
+ }
+
+ internal ICodeGenerator CodeGenerator {
+ get { return descriptionImporter.CodeGenerator; }
+ }
+
+ internal ImportContext ImportContext {
+ get { return descriptionImporter.Context; }
+ }
+#endif
#endregion // Properties
this.classNames = new CodeIdentifiers();;
this.codeNamespace = codeNamespace;
this.codeCompileUnit = codeCompileUnit;
-
+
warnings = (ServiceDescriptionImportWarnings) 0;
bool found = false;
}
}
}
+
+ if (!found)
+ {
+ // Looks like MS.NET generates classes for all bindings if
+ // no services are present
+
+ foreach (ImportInfo info in importInfo)
+ {
+ this.iinfo = info;
+ foreach (Binding b in info.ServiceDescription.Bindings)
+ {
+ this.binding = b;
+ this.service = null;
+ this.port = null;
+ if (!IsBindingSupported ()) continue;
+ found = true;
+ ImportPortBinding (true);
+ }
+ }
+ }
EndNamespace ();
+ if (!found) warnings = ServiceDescriptionImportWarnings.NoCodeGenerated;
return true;
}
void ImportPortBinding (bool multipleBindings)
{
- if (multipleBindings) className = port.Name;
- else className = service.Name;
+ if (port != null) {
+ if (multipleBindings) className = port.Name;
+ else className = service.Name;
+ }
+ else
+ className = binding.Name;
className = classNames.AddUnique (CodeIdentifier.MakeValid (className), port);
+ className = className.Replace ("_x0020_", ""); // MS.NET seems to do this
try
{
CodeTypeDeclaration codeClass = BeginClass ();
codeTypeDeclaration = codeClass;
- AddCodeType (codeClass, port.Documentation);
+ AddCodeType (codeClass, port != null ? port.Documentation : null);
codeClass.Attributes = MemberAttributes.Public;
-
- if (service.Documentation != null && service.Documentation != "")
+
+ if (service != null && service.Documentation != null && service.Documentation != "")
AddComments (codeClass, service.Documentation);
- CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Diagnostics.DebuggerStepThroughAttribute");
- AddCustomAttribute (codeClass, att, true);
-
- att = new CodeAttributeDeclaration ("System.ComponentModel.DesignerCategoryAttribute");
- att.Arguments.Add (GetArg ("code"));
- AddCustomAttribute (codeClass, att, true);
+ if (Style == ServiceDescriptionImportStyle.Client) {
+ CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Diagnostics.DebuggerStepThroughAttribute");
+ AddCustomAttribute (codeClass, att, true);
+
+ att = new CodeAttributeDeclaration ("System.ComponentModel.DesignerCategoryAttribute");
+ att.Arguments.Add (GetArg ("code"));
+ AddCustomAttribute (codeClass, att, true);
+ }
+ else
+ codeClass.TypeAttributes = System.Reflection.TypeAttributes.Abstract | System.Reflection.TypeAttributes.Public;
if (binding.Operations.Count == 0) {
warnings |= ServiceDescriptionImportWarnings.NoMethodsGenerated;
methodName = method.Name;
if (operation.Documentation != null && operation.Documentation != "")
AddComments (method, operation.Documentation);
+#if NET_2_0
+ if (Style == ServiceDescriptionImportStyle.Client)
+ AddAsyncMembers (method.Name, method);
+#endif
}
}
+#if NET_2_0
+ if (Style == ServiceDescriptionImportStyle.Client)
+ AddAsyncTypes ();
+#endif
+
EndClass ();
}
catch (InvalidOperationException ex)
else return msg.Name;
}
- internal string GetServiceUrl (string location)
+ internal void GenerateServiceUrl (string location, CodeStatementCollection stms)
{
- if (ImportInfo.AppSettingUrlKey == null || ImportInfo.AppSettingUrlKey == string.Empty)
- return location;
+ if (ImportInfo.AppSettingUrlKey == null || ImportInfo.AppSettingUrlKey == string.Empty) {
+ if (location != null) {
+ CodeExpression ce = new CodeFieldReferenceExpression (new CodeThisReferenceExpression(), "Url");
+ CodeAssignStatement cas = new CodeAssignStatement (ce, new CodePrimitiveExpression (location));
+ stms.Add (cas);
+ }
+ }
else
{
- string url;
- if (Style == ServiceDescriptionImportStyle.Server) throw new InvalidOperationException ("Cannot set appSettingUrlKey if Style is Server");
- url = ConfigurationSettings.AppSettings [ImportInfo.AppSettingUrlKey];
- if (ImportInfo.AppSettingBaseUrl != null && ImportInfo.AppSettingBaseUrl != string.Empty)
- url += "/" + ImportInfo.AppSettingBaseUrl + "/" + location;
- return url;
+ CodeExpression prop = new CodePropertyReferenceExpression (new CodeTypeReferenceExpression ("System.Configuration.ConfigurationSettings"), "AppSettings");
+ prop = new CodeIndexerExpression (prop, new CodePrimitiveExpression (ImportInfo.AppSettingUrlKey));
+ stms.Add (new CodeVariableDeclarationStatement (typeof(string), "urlSetting", prop));
+
+ CodeExpression urlSetting = new CodeVariableReferenceExpression ("urlSetting");
+ CodeExpression thisUrl = new CodeFieldReferenceExpression (new CodeThisReferenceExpression(), "Url");
+
+ CodeStatement[] trueStms = new CodeStatement [1];
+ CodeExpression ce = urlSetting;
+ CodeExpression cond = new CodeBinaryOperatorExpression (urlSetting, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
+
+ if (ImportInfo.AppSettingBaseUrl != null)
+ ce = new CodeMethodInvokeExpression (new CodeTypeReferenceExpression (typeof(string)), "Concat", ce, new CodePrimitiveExpression (ImportInfo.AppSettingBaseUrl));
+ trueStms [0] = new CodeAssignStatement (thisUrl, ce);
+
+ if (location != null) {
+ CodeStatement[] falseStms = new CodeStatement [1];
+ falseStms [0] = new CodeAssignStatement (thisUrl, new CodePrimitiveExpression (location));
+ stms.Add (new CodeConditionStatement (cond, trueStms, falseStms));
+ }
+ else
+ stms.Add (new CodeConditionStatement (cond, trueStms));
}
}
-
+
void ClasifySchemas (ArrayList importInfo)
{
// I don't like this, but I could not find any other way of clasifying
// Schemas not referenced by any message
foreach (XmlSchema sc in Schemas)
{
- if (ImportsEncodedNamespace (sc))
- soapSchemas.Add (sc);
- else if (!soapSchemas.Contains (sc) && !xmlSchemas.Contains (sc))
- defaultList.Add (sc);
+ if (!soapSchemas.Contains (sc) && !xmlSchemas.Contains (sc)) {
+ if (ImportsEncodedNamespace (sc))
+ soapSchemas.Add (sc);
+ else
+ defaultList.Add (sc);
+ }
}
}
return false;
}
+#if NET_2_0
+
+ void AddAsyncTypes ()
+ {
+ foreach (CodeTypeDeclaration type in asyncTypes)
+ codeNamespace.Types.Add (type);
+ asyncTypes.Clear ();
+ }
+
+ void AddAsyncMembers (string messageName, CodeMemberMethod method)
+ {
+ CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
+ CodePrimitiveExpression enull = new CodePrimitiveExpression (null);
+
+ CodeMemberField codeField = new CodeMemberField (typeof(System.Threading.SendOrPostCallback), messageName + "OperationCompleted");
+ codeField.Attributes = MemberAttributes.Private;
+ CodeTypeDeclaration.Members.Add (codeField);
+
+ // Event arguments class
+
+ string argsClassName = classNames.AddUnique (messageName + "CompletedEventArgs", null);
+ CodeTypeDeclaration argsClass = new CodeTypeDeclaration (argsClassName);
+ argsClass.BaseTypes.Add (new CodeTypeReference ("System.ComponentModel.AsyncCompletedEventArgs"));
+
+ CodeMemberField resultsField = new CodeMemberField (typeof(object[]), "results");
+ resultsField.Attributes = MemberAttributes.Private;
+ argsClass.Members.Add (resultsField);
+
+ CodeConstructor cc = new CodeConstructor ();
+ cc.Attributes = MemberAttributes.Assembly;
+ cc.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object[]), "results"));
+ cc.Parameters.Add (new CodeParameterDeclarationExpression (typeof(System.Exception), "exception"));
+ cc.Parameters.Add (new CodeParameterDeclarationExpression (typeof(bool), "cancelled"));
+ cc.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), "userState"));
+ cc.BaseConstructorArgs.Add (new CodeVariableReferenceExpression ("exception"));
+ cc.BaseConstructorArgs.Add (new CodeVariableReferenceExpression ("cancelled"));
+ cc.BaseConstructorArgs.Add (new CodeVariableReferenceExpression ("userState"));
+ CodeExpression thisResults = new CodeFieldReferenceExpression (ethis, "results");
+ cc.Statements.Add (new CodeAssignStatement (thisResults, new CodeVariableReferenceExpression ("results")));
+ argsClass.Members.Add (cc);
+
+ int ind = 0;
+
+ if (method.ReturnType.BaseType != "System.Void")
+ argsClass.Members.Add (CreateArgsProperty (method.ReturnType, "Result", ind++));
+
+ foreach (CodeParameterDeclarationExpression par in method.Parameters)
+ {
+ if (par.Direction == FieldDirection.Out || par.Direction == FieldDirection.Ref)
+ argsClass.Members.Add (CreateArgsProperty (par.Type, par.Name, ind++));
+ }
+
+ bool needsArgsClass = (ind > 0);
+ if (needsArgsClass)
+ asyncTypes.Add (argsClass);
+ else
+ argsClassName = "System.ComponentModel.AsyncCompletedEventArgs";
+
+ // Event delegate type
+
+ CodeTypeDelegate delegateType = new CodeTypeDelegate (messageName + "CompletedEventHandler");
+ delegateType.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), "sender"));
+ delegateType.Parameters.Add (new CodeParameterDeclarationExpression (argsClassName, "args"));
+
+ // Event member
+
+ CodeMemberEvent codeEvent = new CodeMemberEvent ();
+ codeEvent.Name = messageName + "Completed";
+ codeEvent.Type = new CodeTypeReference (delegateType.Name);
+ CodeTypeDeclaration.Members.Add (codeEvent);
+
+ // Async method (without user state param)
+
+ CodeMemberMethod am = new CodeMemberMethod ();
+ am.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ am.Name = method.Name + "Async";
+ am.ReturnType = new CodeTypeReference (typeof(void));
+ CodeMethodInvokeExpression inv;
+ inv = new CodeMethodInvokeExpression (ethis, am.Name);
+ am.Statements.Add (inv);
+
+ // On...Completed method
+
+ CodeMemberMethod onCompleted = new CodeMemberMethod ();
+ onCompleted.Name = "On" + messageName + "Completed";
+ onCompleted.Attributes = MemberAttributes.Private | MemberAttributes.Final;
+ onCompleted.ReturnType = new CodeTypeReference (typeof(void));
+ onCompleted.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), "arg"));
+
+ CodeConditionStatement anIf = new CodeConditionStatement ();
+
+ CodeExpression eventField = new CodeEventReferenceExpression (ethis, codeEvent.Name);
+ anIf.Condition = new CodeBinaryOperatorExpression (eventField, CodeBinaryOperatorType.IdentityInequality, enull);
+ CodeExpression castedArg = new CodeCastExpression (typeof(System.Web.Services.Protocols.InvokeCompletedEventArgs), new CodeVariableReferenceExpression ("arg"));
+ CodeStatement invokeArgs = new CodeVariableDeclarationStatement (typeof(System.Web.Services.Protocols.InvokeCompletedEventArgs), "invokeArgs", castedArg);
+ anIf.TrueStatements.Add (invokeArgs);
+
+ CodeDelegateInvokeExpression delegateInvoke = new CodeDelegateInvokeExpression ();
+ delegateInvoke.TargetObject = eventField;
+ delegateInvoke.Parameters.Add (ethis);
+ CodeObjectCreateExpression argsInstance = new CodeObjectCreateExpression (argsClassName);
+ CodeExpression invokeArgsVar = new CodeVariableReferenceExpression ("invokeArgs");
+ if (needsArgsClass) argsInstance.Parameters.Add (new CodeFieldReferenceExpression (invokeArgsVar, "Results"));
+ argsInstance.Parameters.Add (new CodeFieldReferenceExpression (invokeArgsVar, "Error"));
+ argsInstance.Parameters.Add (new CodeFieldReferenceExpression (invokeArgsVar, "Cancelled"));
+ argsInstance.Parameters.Add (new CodeFieldReferenceExpression (invokeArgsVar, "UserState"));
+ delegateInvoke.Parameters.Add (argsInstance);
+ anIf.TrueStatements.Add (delegateInvoke);
+
+ onCompleted.Statements.Add (anIf);
+
+ // Async method
+
+ CodeMemberMethod asyncMethod = new CodeMemberMethod ();
+ asyncMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ asyncMethod.Name = method.Name + "Async";
+ asyncMethod.ReturnType = new CodeTypeReference (typeof(void));
+
+ CodeExpression delegateField = new CodeFieldReferenceExpression (ethis, codeField.Name);
+ anIf = new CodeConditionStatement ();
+ anIf.Condition = new CodeBinaryOperatorExpression (delegateField, CodeBinaryOperatorType.IdentityEquality, enull);;
+ CodeExpression delegateRef = new CodeMethodReferenceExpression (ethis, onCompleted.Name);
+ CodeExpression newDelegate = new CodeObjectCreateExpression (typeof(System.Threading.SendOrPostCallback), delegateRef);
+ CodeAssignStatement cas = new CodeAssignStatement (delegateField, newDelegate);
+ anIf.TrueStatements.Add (cas);
+ asyncMethod.Statements.Add (anIf);
+
+ CodeArrayCreateExpression paramsArray = new CodeArrayCreateExpression (typeof(object));
+
+ // Assign parameters
+
+ CodeIdentifiers paramsIds = new CodeIdentifiers ();
+
+ foreach (CodeParameterDeclarationExpression par in method.Parameters)
+ {
+ paramsIds.Add (par.Name, null);
+ if (par.Direction == FieldDirection.In || par.Direction == FieldDirection.Ref) {
+ CodeParameterDeclarationExpression inpar = new CodeParameterDeclarationExpression (par.Type, par.Name);
+ am.Parameters.Add (inpar);
+ asyncMethod.Parameters.Add (inpar);
+ inv.Parameters.Add (new CodeVariableReferenceExpression (par.Name));
+ paramsArray.Initializers.Add (new CodeVariableReferenceExpression (par.Name));
+ }
+ }
+
+
+ inv.Parameters.Add (enull);
+
+ string userStateName = paramsIds.AddUnique ("userState", null);
+ asyncMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), userStateName));
+
+ CodeExpression userStateVar = new CodeVariableReferenceExpression (userStateName);
+ asyncMethod.Statements.Add (BuildInvokeAsync (messageName, paramsArray, delegateField, userStateVar));
+
+ CodeTypeDeclaration.Members.Add (am);
+ CodeTypeDeclaration.Members.Add (asyncMethod);
+ CodeTypeDeclaration.Members.Add (onCompleted);
+
+ asyncTypes.Add (delegateType);
+ }
+
+ CodeMemberProperty CreateArgsProperty (CodeTypeReference type, string name, int ind)
+ {
+ CodeMemberProperty prop = new CodeMemberProperty ();
+ prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ prop.HasGet = true;
+ prop.HasSet = false;
+ prop.Name = name;
+ prop.Type = type;
+ CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
+ CodeExpression thisResults = new CodeFieldReferenceExpression (ethis, "results");
+ prop.GetStatements.Add (new CodeMethodInvokeExpression (ethis, "RaiseExceptionIfNecessary"));
+ CodeArrayIndexerExpression arrValue = new CodeArrayIndexerExpression (thisResults, new CodePrimitiveExpression (ind));
+ CodeExpression retval = new CodeCastExpression (type, arrValue);
+ prop.GetStatements.Add (new CodeMethodReturnStatement (retval));
+ return prop;
+ }
+
+ internal virtual CodeExpression BuildInvokeAsync (string messageName, CodeArrayCreateExpression paramsArray, CodeExpression delegateField, CodeExpression userStateVar)
+ {
+ CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
+ CodeMethodInvokeExpression inv2 = new CodeMethodInvokeExpression (ethis, "InvokeAsync");
+ inv2.Parameters.Add (new CodePrimitiveExpression (messageName));
+ inv2.Parameters.Add (paramsArray);
+ inv2.Parameters.Add (delegateField);
+ inv2.Parameters.Add (userStateVar);
+ return inv2;
+ }
+#endif
+
[MonoTODO]
public void AddExtensionWarningComments (CodeCommentStatementCollection comments, ServiceDescriptionFormatExtensionCollection extensions)
{