a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
863 lines
28 KiB
C#
863 lines
28 KiB
C#
//
|
|
// System.Web.Services.Description.ProtocolImporter.cs
|
|
//
|
|
// Author:
|
|
// Tim Coleman (tim@timcoleman.com)
|
|
// Lluis Sanchez Gual (lluis@ximian.com)
|
|
//
|
|
// 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;
|
|
using System.Xml;
|
|
using System.Xml.Schema;
|
|
using System.Collections;
|
|
using System.Configuration;
|
|
|
|
namespace System.Web.Services.Description {
|
|
public abstract class ProtocolImporter {
|
|
|
|
#region Fields
|
|
|
|
Binding binding;
|
|
string className;
|
|
CodeIdentifiers classNames;
|
|
CodeNamespace codeNamespace;
|
|
CodeTypeDeclaration codeTypeDeclaration;
|
|
Message inputMessage;
|
|
string methodName;
|
|
Operation operation;
|
|
OperationBinding operationBinding;
|
|
Message outputMessage;
|
|
Port port;
|
|
PortType portType;
|
|
Service service;
|
|
ServiceDescriptionImportWarnings warnings = (ServiceDescriptionImportWarnings)0;
|
|
ServiceDescriptionImporter descriptionImporter;
|
|
ImportInfo iinfo;
|
|
XmlSchemas xmlSchemas;
|
|
XmlSchemas soapSchemas;
|
|
|
|
#if NET_2_0
|
|
ArrayList asyncTypes = new ArrayList ();
|
|
#endif
|
|
|
|
#endregion // Fields
|
|
|
|
#region Constructors
|
|
|
|
protected ProtocolImporter ()
|
|
{
|
|
}
|
|
|
|
#endregion // Constructors
|
|
|
|
#region Properties
|
|
|
|
[MonoTODO]
|
|
public XmlSchemas AbstractSchemas {
|
|
get { return descriptionImporter.Schemas; }
|
|
}
|
|
|
|
public Binding Binding {
|
|
get { return binding; }
|
|
}
|
|
|
|
public string ClassName {
|
|
get { return className; }
|
|
}
|
|
|
|
public CodeIdentifiers ClassNames {
|
|
get { return classNames; }
|
|
}
|
|
|
|
public CodeNamespace CodeNamespace {
|
|
get { return codeNamespace; }
|
|
}
|
|
|
|
public CodeTypeDeclaration CodeTypeDeclaration {
|
|
get { return codeTypeDeclaration; }
|
|
}
|
|
|
|
[MonoTODO]
|
|
public XmlSchemas ConcreteSchemas {
|
|
get { return descriptionImporter.Schemas; }
|
|
}
|
|
|
|
public Message InputMessage {
|
|
get { return inputMessage; }
|
|
}
|
|
|
|
public string MethodName {
|
|
get { return methodName; }
|
|
}
|
|
|
|
public Operation Operation {
|
|
get { return operation; }
|
|
}
|
|
|
|
public OperationBinding OperationBinding {
|
|
get { return operationBinding; }
|
|
}
|
|
|
|
public Message OutputMessage {
|
|
get { return outputMessage; }
|
|
}
|
|
|
|
public Port Port {
|
|
get { return port; }
|
|
}
|
|
|
|
public PortType PortType {
|
|
get { return portType; }
|
|
}
|
|
|
|
public abstract string ProtocolName {
|
|
get;
|
|
}
|
|
|
|
public XmlSchemas Schemas {
|
|
get { return descriptionImporter.Schemas; }
|
|
}
|
|
|
|
public Service Service {
|
|
get { return service; }
|
|
}
|
|
|
|
public ServiceDescriptionCollection ServiceDescriptions {
|
|
get { return descriptionImporter.ServiceDescriptions; }
|
|
}
|
|
|
|
public ServiceDescriptionImportStyle Style {
|
|
get { return descriptionImporter.Style; }
|
|
}
|
|
|
|
public ServiceDescriptionImportWarnings Warnings {
|
|
get { return warnings; }
|
|
set { warnings = value; }
|
|
}
|
|
|
|
internal ImportInfo ImportInfo
|
|
{
|
|
get { return iinfo; }
|
|
}
|
|
|
|
internal XmlSchemas LiteralSchemas
|
|
{
|
|
get { return xmlSchemas; }
|
|
}
|
|
|
|
internal XmlSchemas EncodedSchemas
|
|
{
|
|
get { return soapSchemas; }
|
|
}
|
|
|
|
#if NET_2_0
|
|
internal CodeGenerationOptions CodeGenerationOptions {
|
|
get { return descriptionImporter.CodeGenerationOptions; }
|
|
}
|
|
|
|
internal CodeDomProvider CodeGenerator {
|
|
get { return descriptionImporter.CodeGenerator; }
|
|
}
|
|
|
|
internal ImportContext ImportContext {
|
|
get { return descriptionImporter.Context; }
|
|
}
|
|
#endif
|
|
|
|
#endregion // Properties
|
|
|
|
#region Methods
|
|
|
|
internal bool Import (ServiceDescriptionImporter descriptionImporter, CodeNamespace codeNamespace, ArrayList importInfo)
|
|
{
|
|
this.descriptionImporter = descriptionImporter;
|
|
this.classNames = new CodeIdentifiers();;
|
|
this.codeNamespace = codeNamespace;
|
|
|
|
warnings = (ServiceDescriptionImportWarnings) 0;
|
|
|
|
bool found = false;
|
|
|
|
ClasifySchemas (importInfo);
|
|
|
|
BeginNamespace ();
|
|
|
|
foreach (ImportInfo info in importInfo)
|
|
{
|
|
foreach (Service service in info.ServiceDescription.Services)
|
|
{
|
|
this.service = service;
|
|
int bindingCount = 0;
|
|
foreach (Port port in service.Ports)
|
|
{
|
|
binding = ServiceDescriptions.GetBinding (port.Binding);
|
|
if (IsBindingSupported ()) bindingCount ++;
|
|
}
|
|
|
|
foreach (Port port in service.Ports)
|
|
{
|
|
this.iinfo = info;
|
|
this.port = port;
|
|
binding = ServiceDescriptions.GetBinding (port.Binding);
|
|
if (!IsBindingSupported ()) continue;
|
|
|
|
found = true;
|
|
ImportPortBinding (bindingCount > 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 found;
|
|
}
|
|
|
|
void ImportPortBinding (bool multipleBindings)
|
|
{
|
|
if (port != null) {
|
|
if (multipleBindings) className = binding.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
|
|
{
|
|
portType = ServiceDescriptions.GetPortType (binding.Type);
|
|
if (portType == null) throw new Exception ("Port type not found: " + binding.Type);
|
|
|
|
CodeTypeDeclaration codeClass = BeginClass ();
|
|
codeTypeDeclaration = codeClass;
|
|
AddCodeType (codeClass, port != null ? port.Documentation : null);
|
|
codeClass.Attributes = MemberAttributes.Public;
|
|
|
|
if (service != null && service.Documentation != null && service.Documentation != "")
|
|
AddComments (codeClass, service.Documentation);
|
|
|
|
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;
|
|
return;
|
|
}
|
|
|
|
foreach (OperationBinding oper in binding.Operations)
|
|
{
|
|
operationBinding = oper;
|
|
operation = FindPortOperation ();
|
|
if (operation == null)
|
|
throw new Exception ("Operation " + operationBinding.Name + " not found in portType " + PortType.Name);
|
|
|
|
inputMessage = null;
|
|
outputMessage = null;
|
|
|
|
foreach (OperationMessage omsg in operation.Messages)
|
|
{
|
|
Message msg = ServiceDescriptions.GetMessage (omsg.Message);
|
|
if (msg == null) throw new Exception ("Message not found: " + omsg.Message);
|
|
|
|
if (omsg is OperationInput)
|
|
inputMessage = msg;
|
|
else
|
|
outputMessage = msg;
|
|
}
|
|
|
|
CodeMemberMethod method = GenerateMethod ();
|
|
|
|
if (method != null)
|
|
{
|
|
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)
|
|
{
|
|
warnings |= ServiceDescriptionImportWarnings.NoCodeGenerated;
|
|
UnsupportedBindingWarning (ex.Message);
|
|
}
|
|
}
|
|
|
|
Operation FindPortOperation ()
|
|
{
|
|
string inMessage = null;
|
|
string outMessage = null;
|
|
int numMsg = 1;
|
|
|
|
if (operationBinding.Input == null) throw new InvalidOperationException ("Input operation binding not found");
|
|
inMessage = (operationBinding.Input.Name != null) ? operationBinding.Input.Name : operationBinding.Name;
|
|
|
|
if (operationBinding.Output != null) {
|
|
outMessage = (operationBinding.Output.Name != null) ? operationBinding.Output.Name : operationBinding.Name;
|
|
numMsg++;
|
|
}
|
|
|
|
string operName = operationBinding.Name;
|
|
|
|
Operation foundOper = null;
|
|
foreach (Operation oper in PortType.Operations)
|
|
{
|
|
if (oper.Name == operName)
|
|
{
|
|
int hits = 0;
|
|
foreach (OperationMessage omsg in oper.Messages)
|
|
{
|
|
if (omsg is OperationInput && GetOperMessageName (omsg, operName) == inMessage) hits++;
|
|
if (omsg is OperationOutput && GetOperMessageName (omsg, operName) == outMessage) hits++;
|
|
}
|
|
if (hits == numMsg) return oper;
|
|
foundOper = oper;
|
|
}
|
|
}
|
|
return foundOper;
|
|
}
|
|
|
|
string GetOperMessageName (OperationMessage msg, string operName)
|
|
{
|
|
if (msg.Name == null) return operName;
|
|
else return msg.Name;
|
|
}
|
|
|
|
internal void GenerateServiceUrl (string location, CodeStatementCollection stms)
|
|
{
|
|
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
|
|
{
|
|
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 between encoded and literal.
|
|
|
|
xmlSchemas = new XmlSchemas ();
|
|
soapSchemas = new XmlSchemas ();
|
|
|
|
foreach (ImportInfo info in importInfo)
|
|
{
|
|
foreach (Service service in info.ServiceDescription.Services)
|
|
{
|
|
foreach (Port port in service.Ports)
|
|
{
|
|
this.iinfo = info;
|
|
this.port = port;
|
|
binding = ServiceDescriptions.GetBinding (port.Binding);
|
|
if (binding == null) continue;
|
|
portType = ServiceDescriptions.GetPortType (binding.Type);
|
|
if (portType == null) continue;
|
|
|
|
foreach (OperationBinding oper in binding.Operations)
|
|
{
|
|
operationBinding = oper;
|
|
operation = FindPortOperation ();
|
|
if (operation == null) continue;
|
|
|
|
foreach (OperationMessage omsg in operation.Messages)
|
|
{
|
|
Message msg = ServiceDescriptions.GetMessage (omsg.Message);
|
|
if (msg == null) continue;
|
|
|
|
if (omsg is OperationInput)
|
|
inputMessage = msg;
|
|
else
|
|
outputMessage = msg;
|
|
}
|
|
|
|
if (GetMessageEncoding (oper.Input) == SoapBindingUse.Encoded)
|
|
AddMessageSchema (soapSchemas, oper.Input, inputMessage);
|
|
else
|
|
AddMessageSchema (xmlSchemas, oper.Input, inputMessage);
|
|
|
|
if (oper.Output != null) {
|
|
if (GetMessageEncoding (oper.Output) == SoapBindingUse.Encoded)
|
|
AddMessageSchema (soapSchemas, oper.Output, outputMessage);
|
|
else
|
|
AddMessageSchema (xmlSchemas, oper.Output, outputMessage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
XmlSchemas defaultList = xmlSchemas;
|
|
|
|
if (xmlSchemas.Count == 0 && soapSchemas.Count > 0)
|
|
defaultList = soapSchemas;
|
|
|
|
// Schemas not referenced by any message
|
|
foreach (XmlSchema sc in Schemas)
|
|
{
|
|
if (!soapSchemas.Contains (sc) && !xmlSchemas.Contains (sc)) {
|
|
if (ImportsEncodedNamespace (sc))
|
|
soapSchemas.Add (sc);
|
|
else
|
|
defaultList.Add (sc);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AddMessageSchema (XmlSchemas schemas, MessageBinding mb, Message msg)
|
|
{
|
|
foreach (MessagePart part in msg.Parts)
|
|
{
|
|
if (part.Element != XmlQualifiedName.Empty)
|
|
AddIncludingSchema (schemas, part.Element.Namespace);
|
|
else if (part.Type != XmlQualifiedName.Empty)
|
|
AddIncludingSchema (schemas, part.Type.Namespace);
|
|
}
|
|
SoapBodyBinding sbb = mb.Extensions.Find (typeof(SoapBodyBinding)) as SoapBodyBinding;
|
|
if (sbb != null) AddIncludingSchema (schemas, sbb.Namespace);
|
|
}
|
|
|
|
void AddIncludingSchema (XmlSchemas list, string ns)
|
|
{
|
|
foreach (XmlSchema sc in Schemas) {
|
|
if (sc.TargetNamespace == ns && !list.Contains (sc)) {
|
|
list.Add (sc);
|
|
foreach (XmlSchemaObject ob in sc.Includes) {
|
|
XmlSchemaImport import = ob as XmlSchemaImport;
|
|
if (import != null) AddIncludingSchema (list, import.Namespace);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SoapBindingUse GetMessageEncoding (MessageBinding mb)
|
|
{
|
|
SoapBodyBinding sbb = mb.Extensions.Find (typeof(SoapBodyBinding)) as SoapBodyBinding;
|
|
if (sbb == null)
|
|
{
|
|
if (mb is InputBinding) return SoapBindingUse.Encoded;
|
|
else return SoapBindingUse.Literal;
|
|
}
|
|
else
|
|
if (sbb.Use == SoapBindingUse.Encoded) return SoapBindingUse.Encoded;
|
|
else
|
|
return SoapBindingUse.Literal;
|
|
}
|
|
|
|
bool ImportsEncodedNamespace (XmlSchema sc)
|
|
{
|
|
foreach (XmlSchemaObject ob in sc.Includes)
|
|
{
|
|
XmlSchemaImport import = ob as XmlSchemaImport;
|
|
if (import == null)
|
|
continue;
|
|
#if NET_2_0
|
|
if (import.Namespace == Soap11BindingExtensionReflector.EncodingNamespace
|
|
|| import.Namespace == Soap12BindingExtensionReflector.EncodingNamespace)
|
|
#else
|
|
if (import.Namespace == Soap11BindingExtensionReflector.EncodingNamespace)
|
|
#endif
|
|
return true;
|
|
}
|
|
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.Attributes |= MemberAttributes.Public;
|
|
#if NET_2_0
|
|
argsClass.IsPartial = true;
|
|
#endif
|
|
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.Attributes |= MemberAttributes.Public;
|
|
delegateType.Parameters.Add (new CodeParameterDeclarationExpression (typeof(object), "sender"));
|
|
delegateType.Parameters.Add (new CodeParameterDeclarationExpression (argsClassName, "args"));
|
|
|
|
// Event member
|
|
|
|
CodeMemberEvent codeEvent = new CodeMemberEvent ();
|
|
codeEvent.Attributes = codeEvent.Attributes & ~MemberAttributes.AccessMask | MemberAttributes.Public;
|
|
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)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
protected abstract CodeTypeDeclaration BeginClass ();
|
|
|
|
protected virtual void BeginNamespace ()
|
|
{
|
|
}
|
|
|
|
protected virtual void EndClass ()
|
|
{
|
|
}
|
|
|
|
protected virtual void EndNamespace ()
|
|
{
|
|
}
|
|
|
|
protected abstract CodeMemberMethod GenerateMethod ();
|
|
protected abstract bool IsBindingSupported ();
|
|
protected abstract bool IsOperationFlowSupported (OperationFlow flow);
|
|
|
|
[MonoTODO]
|
|
public Exception OperationBindingSyntaxException (string text)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
[MonoTODO]
|
|
public Exception OperationSyntaxException (string text)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
public void UnsupportedBindingWarning (string text)
|
|
{
|
|
warnings |= ServiceDescriptionImportWarnings.UnsupportedBindingsIgnored;
|
|
AddGlobalComments ("WARNING: Could not generate proxy for binding " + binding.Name + ". " + text);
|
|
}
|
|
|
|
public void UnsupportedOperationBindingWarning (string text)
|
|
{
|
|
warnings |= ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored;
|
|
AddGlobalComments ("WARNING: Could not generate operation binding " + OperationBinding.Name + ". " + text);
|
|
}
|
|
|
|
public void UnsupportedOperationWarning (string text)
|
|
{
|
|
warnings |= ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored;
|
|
AddGlobalComments ("WARNING: Could not generate operation " + Operation.Name + ". " + text);
|
|
}
|
|
|
|
void AddGlobalComments (string comments)
|
|
{
|
|
codeNamespace.Comments.Add (new CodeCommentStatement (comments, false));
|
|
}
|
|
|
|
void AddComments (CodeTypeMember member, string comments)
|
|
{
|
|
if (comments == null || comments == "") member.Comments.Add (new CodeCommentStatement ("<remarks/>", true));
|
|
else member.Comments.Add (new CodeCommentStatement ("<remarks>\n" + comments + "\n</remarks>", true));
|
|
}
|
|
|
|
void AddCodeType (CodeTypeDeclaration type, string comments)
|
|
{
|
|
AddComments (type, comments);
|
|
codeNamespace.Types.Add (type);
|
|
}
|
|
|
|
internal void AddCustomAttribute (CodeTypeMember ctm, CodeAttributeDeclaration att, bool addIfNoParams)
|
|
{
|
|
if (att.Arguments.Count == 0 && !addIfNoParams) return;
|
|
|
|
if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
|
|
ctm.CustomAttributes.Add (att);
|
|
}
|
|
|
|
internal void AddCustomAttribute (CodeTypeMember ctm, string name, params CodeAttributeArgument[] args)
|
|
{
|
|
if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
|
|
ctm.CustomAttributes.Add (new CodeAttributeDeclaration (name, args));
|
|
}
|
|
|
|
internal CodeAttributeArgument GetArg (string name, object value)
|
|
{
|
|
return new CodeAttributeArgument (name, new CodePrimitiveExpression(value));
|
|
}
|
|
|
|
internal CodeAttributeArgument GetEnumArg (string name, string enumType, string enumValue)
|
|
{
|
|
return new CodeAttributeArgument (name, new CodeFieldReferenceExpression (new CodeTypeReferenceExpression(enumType), enumValue));
|
|
}
|
|
|
|
internal CodeAttributeArgument GetArg (object value)
|
|
{
|
|
return new CodeAttributeArgument (new CodePrimitiveExpression(value));
|
|
}
|
|
|
|
internal CodeAttributeArgument GetTypeArg (string name, string typeName)
|
|
{
|
|
return new CodeAttributeArgument (name, new CodeTypeOfExpression(typeName));
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|