using System.CodeDom;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.ComponentModel;
using System.Configuration;
+using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
+using System.Threading;
using System.Xml.Schema;
using System.Xml.Serialization;
{
CodeCompileUnit ccu;
ConfigurationType config;
+ CodeIdentifiers identifiers = new CodeIdentifiers ();
Collection<MetadataConversionError> errors
= new Collection<MetadataConversionError> ();
Dictionary<string,string> nsmappings
= new Dictionary<string,string> ();
Dictionary<ContractDescription,Type> referenced_types
= new Dictionary<ContractDescription,Type> ();
+ Dictionary<ContractDescription,ContractCacheEntry> generated_contracts
+ = new Dictionary<ContractDescription,ContractCacheEntry> ();
ServiceContractGenerationOptions options;
- Dictionary<QName, QName> imported_names = null;
+ Dictionary<QName, QName> imported_names
+ = new Dictionary<QName, QName> ();
ServiceContractGenerationContext contract_context;
List<OPair> operation_contexts = new List<OPair> ();
+ XsdDataContractImporter data_contract_importer;
+ XmlSerializerMessageContractImporterInternal xml_serialization_importer;
+
+ class ContractCacheEntry {
+ public ContractDescription Contract {
+ get;
+ private set;
+ }
+
+ public string ConfigurationName {
+ get;
+ private set;
+ }
+
+ public CodeTypeDeclaration TypeDeclaration {
+ get;
+ private set;
+ }
+
+ public bool GeneratedContractType {
+ get; set;
+ }
+
+ public CodeTypeReference GetReference ()
+ {
+ return reference;
+ }
+
+ public ContractCacheEntry (ContractDescription cd, string config,
+ CodeTypeDeclaration tdecl)
+ {
+ Contract = cd;
+ ConfigurationName = config;
+ TypeDeclaration = tdecl;
+ reference = new CodeTypeReference (tdecl.Name);
+ }
+
+ readonly CodeTypeReference reference;
+ }
+
public ServiceContractGenerator ()
: this (null, null)
{
}
- public ServiceContractGenerator (CodeCompileUnit ccu)
- : this (ccu, null)
+ public ServiceContractGenerator (CodeCompileUnit targetCompileUnit)
+ : this (targetCompileUnit, null)
{
}
- public ServiceContractGenerator (ConfigurationType config)
- : this (null, config)
+ public ServiceContractGenerator (ConfigurationType targetConfig)
+ : this (null, targetConfig)
{
}
- public ServiceContractGenerator (CodeCompileUnit ccu, ConfigurationType config)
+ public ServiceContractGenerator (CodeCompileUnit targetCompileUnit, ConfigurationType targetConfig)
{
- if (ccu == null)
+ if (targetCompileUnit == null)
this.ccu = new CodeCompileUnit ();
else
- this.ccu = ccu;
- this.config = config;
+ this.ccu = targetCompileUnit;
+ this.config = targetConfig;
Options |= ServiceContractGenerationOptions.ChannelInterface |
ServiceContractGenerationOptions.ClientClass;
}
}
bool GenerateAsync {
- get { return (options & ServiceContractGenerationOptions.AsynchronousMethods) != 0; }
+ get { return GenerateEventBasedAsync || (options & ServiceContractGenerationOptions.AsynchronousMethods) != 0; }
+ }
+
+ bool GenerateEventBasedAsync {
+ get { return (options & ServiceContractGenerationOptions.EventBasedAsynchronousMethods) != 0; }
}
public Dictionary<ContractDescription,Type> ReferencedTypes {
get { return ccu; }
}
- [MonoTODO]
public void GenerateBinding (Binding binding,
out string bindingSectionName,
out string configurationName)
{
- throw new NotImplementedException ();
+ if (config == null)
+ throw new InvalidOperationException ();
+
+ var element = ConfigUtil.FindCollectionElement (binding, config);
+ if (element == null)
+ throw new InvalidOperationException ();
+
+ bindingSectionName = element.BindingName;
+
+ int idx = 0;
+ configurationName = binding.Name;
+ while (element.ContainsKey (configurationName))
+ configurationName = binding.Name + (++idx);
+
+ if (!element.TryAdd (configurationName, binding, config))
+ throw new InvalidOperationException ();
}
#region Service Contract Type
ContractDescription contractDescription)
{
CodeNamespace cns = GetNamespace (contractDescription.Namespace);
- imported_names = new Dictionary<QName, QName> ();
- var ret = ExportInterface (contractDescription, cns);
+ var cache = ExportInterface_internal (contractDescription, cns);
+ if (cache.GeneratedContractType)
+ return cache.GetReference ();
// FIXME: handle duplex callback
if ((Options & ServiceContractGenerationOptions.ClientClass) != 0)
GenerateProxyClass (contractDescription, cns);
+ if (data_contract_importer != null)
+ MergeCompileUnit (data_contract_importer.CodeCompileUnit, ccu);
+ if (xml_serialization_importer != null)
+ MergeCompileUnit (xml_serialization_importer.CodeCompileUnit, ccu);
+
// Process extensions. Class first, then methods.
// (built-in ones must present before processing class extensions).
foreach (var cb in contractDescription.Behaviors) {
foreach (var opair in operation_contexts)
opair.Key.GenerateOperation (opair.Value);
- return ret;
+ cache.GeneratedContractType = true;
+ return cache.GetReference ();
}
- CodeNamespace GetNamespace (string ns)
+ CodeNamespace GetNamespace (string contractNs)
{
- if (ns == null)
- ns = String.Empty;
+ if (contractNs == null)
+ contractNs = String.Empty;
+ string csharpNs;
+ if (nsmappings.ContainsKey (contractNs))
+ csharpNs = nsmappings [contractNs];
+ else if (nsmappings.ContainsKey ("*"))
+ csharpNs = nsmappings ["*"];
+ else
+ csharpNs = string.Empty;
foreach (CodeNamespace cns in ccu.Namespaces)
- if (cns.Name == ns)
+ if (cns.Name == csharpNs)
return cns;
CodeNamespace ncns = new CodeNamespace ();
- //ncns.Name = ns;
+ ncns.Name = csharpNs;
ccu.Namespaces.Add (ncns);
return ncns;
}
string name = cd.Name + "Client";
if (name [0] == 'I')
name = name.Substring (1);
+ name = identifiers.AddUnique (name, null);
CodeTypeDeclaration type = GetTypeDeclaration (cns, name);
if (type != null)
return; // already imported
// service contract methods
AddImplementationClientMethods (type, cd);
+
+ if (GenerateEventBasedAsync)
+ foreach (var od in cd.Operations)
+ GenerateEventBasedAsyncSupport (type, od, cns);
}
void GenerateChannelInterface (ContractDescription cd, CodeNamespace cns)
{
string name = cd.Name + "Channel";
+ name = identifiers.AddUnique (name, null);
CodeTypeDeclaration type = GetTypeDeclaration (cns, name);
if (type != null)
return;
CodeTypeReference ExportInterface (ContractDescription cd, CodeNamespace cns)
{
- CodeTypeDeclaration type = GetTypeDeclaration (cns, cd.Name);
- if (type != null)
- return new CodeTypeReference (type.Name);
- type = new CodeTypeDeclaration ();
+ var cache = ExportInterface_internal (cd, cns);
+ return cache.GetReference ();
+ }
+
+ ContractCacheEntry ExportInterface_internal (ContractDescription cd, CodeNamespace cns)
+ {
+ if (generated_contracts.ContainsKey (cd))
+ return generated_contracts [cd];
+
+ var type = new CodeTypeDeclaration ();
type.TypeAttributes = TypeAttributes.Interface;
type.TypeAttributes |= TypeAttributes.Public;
cns.Types.Add (type);
- type.Name = cd.Name;
+ type.Name = identifiers.AddUnique (cd.Name, null);
+
+ var configName = type.Name;
CodeAttributeDeclaration ad =
new CodeAttributeDeclaration (
new CodeTypeReference (
- typeof (ServiceContractAttribute)));
+ typeof (ServiceContractAttribute)));
ad.Arguments.Add (new CodeAttributeArgument ("Namespace", new CodePrimitiveExpression (cd.Namespace)));
+ ad.Arguments.Add (new CodeAttributeArgument ("ConfigurationName", new CodePrimitiveExpression (configName)));
type.CustomAttributes.Add (ad);
contract_context = new ServiceContractGenerationContext (this, cd, type);
-
+
AddOperationMethods (type, cd);
- return new CodeTypeReference (type.Name);
+ var cache = new ContractCacheEntry (cd, configName, type);
+ generated_contracts.Add (cd, cache);
+ return cache;
}
void AddBeginAsyncArgs (CodeMemberMethod cm)
foreach (OperationDescription od in cd.Operations) {
CodeMemberMethod syncMethod = null, beginMethod = null, endMethod = null;
- CodeMemberMethod cm = new CodeMemberMethod ();
- type.Members.Add (cm);
- if (GenerateAsync) {
- cm.Name = "Begin" + od.Name;
- beginMethod = cm;
- } else {
- cm.Name = od.Name;
- syncMethod = cm;
- }
CodeTypeReference returnTypeFromMessageContract = null;
+ syncMethod = GenerateOperationMethod (type, cd, od, false, out returnTypeFromMessageContract);
+ type.Members.Add (syncMethod);
- if (od.SyncMethod != null) {
- ExportParameters (cm, od.SyncMethod.GetParameters ());
- if (GenerateAsync) {
- AddBeginAsyncArgs (cm);
- cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
- }
- else
- cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
- } else {
- ExportMessages (od.Messages, cm, false);
- returnTypeFromMessageContract = cm.ReturnType;
- if (GenerateAsync) {
- AddBeginAsyncArgs (cm);
- cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
- }
- }
-
- // [OperationContract (Action = "...", ReplyAction = "..")]
- CodeAttributeDeclaration ad =
- new CodeAttributeDeclaration (
- new CodeTypeReference (
- typeof (OperationContractAttribute)));
- foreach (MessageDescription md in od.Messages) {
- if (md.Direction == MessageDirection.Input)
- ad.Arguments.Add (new CodeAttributeArgument ("Action", new CodePrimitiveExpression (md.Action)));
- else
- ad.Arguments.Add (new CodeAttributeArgument ("ReplyAction", new CodePrimitiveExpression (md.Action)));
- }
- if (GenerateAsync)
- ad.Arguments.Add (new CodeAttributeArgument ("AsyncPattern", new CodePrimitiveExpression (true)));
- cm.CustomAttributes.Add (ad);
-
- // For async mode, add EndXxx() too.
if (GenerateAsync) {
+ beginMethod = GenerateOperationMethod (type, cd, od, true, out returnTypeFromMessageContract);
+ type.Members.Add (beginMethod);
- cm = new CodeMemberMethod ();
+ var cm = new CodeMemberMethod ();
type.Members.Add (cm);
cm.Name = "End" + od.Name;
endMethod = cm;
}
}
+ CodeMemberMethod GenerateOperationMethod (CodeTypeDeclaration type, ContractDescription cd, OperationDescription od, bool async, out CodeTypeReference returnType)
+ {
+ CodeMemberMethod cm = new CodeMemberMethod ();
+
+ if (od.Behaviors.Find<XmlSerializerMappingBehavior> () != null)
+ cm.CustomAttributes.Add (new CodeAttributeDeclaration (new CodeTypeReference (typeof (XmlSerializerFormatAttribute))));
+
+ if (async)
+ cm.Name = "Begin" + od.Name;
+ else
+ cm.Name = od.Name;
+
+ if (od.SyncMethod != null) {
+ ExportParameters (cm, od.SyncMethod.GetParameters ());
+ if (async) {
+ AddBeginAsyncArgs (cm);
+ cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
+ }
+ else
+ cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
+ returnType = new CodeTypeReference (od.SyncMethod.ReturnType);
+ } else {
+ ExportMessages (od.Messages, cm, false);
+ returnType = cm.ReturnType;
+ if (async) {
+ AddBeginAsyncArgs (cm);
+ cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
+ }
+ }
+
+ // [OperationContract (Action = "...", ReplyAction = "..")]
+ var ad = new CodeAttributeDeclaration (new CodeTypeReference (typeof (OperationContractAttribute)));
+ foreach (MessageDescription md in od.Messages) {
+ if (md.Direction == MessageDirection.Input)
+ ad.Arguments.Add (new CodeAttributeArgument ("Action", new CodePrimitiveExpression (md.Action)));
+ else
+ ad.Arguments.Add (new CodeAttributeArgument ("ReplyAction", new CodePrimitiveExpression (md.Action)));
+ }
+ if (async)
+ ad.Arguments.Add (new CodeAttributeArgument ("AsyncPattern", new CodePrimitiveExpression (true)));
+ cm.CustomAttributes.Add (ad);
+
+ return cm;
+ }
+
void ExportParameters (CodeMemberMethod method, ParameterInfo [] parameters)
{
foreach (ParameterInfo pi in parameters)
void AddImplementationClientMethods (CodeTypeDeclaration type, ContractDescription cd)
{
foreach (OperationDescription od in cd.Operations) {
- CodeMemberMethod cm = new CodeMemberMethod ();
- type.Members.Add (cm);
- if (GenerateAsync)
- cm.Name = "Begin" + od.Name;
- else
- cm.Name = od.Name;
- cm.Attributes = MemberAttributes.Public
- | MemberAttributes.Final;
+ CodeMemberMethod cm;
CodeTypeReference returnTypeFromMessageContract = null;
+ cm = GenerateImplementationClientMethod (type, cd, od, false, out returnTypeFromMessageContract);
+ type.Members.Add (cm);
- List<CodeExpression> args = new List<CodeExpression> ();
- if (od.SyncMethod != null) {
- ParameterInfo [] pars = od.SyncMethod.GetParameters ();
- ExportParameters (cm, pars);
- cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
- int i = 0;
- foreach (ParameterInfo pi in pars)
- args.Add (new CodeArgumentReferenceExpression (pi.Name));
- } else {
- args.AddRange (ExportMessages (od.Messages, cm, true));
- returnTypeFromMessageContract = cm.ReturnType;
- if (GenerateAsync) {
- AddBeginAsyncArgs (cm);
- cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
- }
- }
- if (GenerateAsync) {
- args.Add (new CodeArgumentReferenceExpression ("asyncCallback"));
- args.Add (new CodeArgumentReferenceExpression ("userState"));
- }
-
- CodeExpression call = new CodeMethodInvokeExpression (
- new CodePropertyReferenceExpression (
- new CodeBaseReferenceExpression (),
- "Channel"),
- cm.Name,
- args.ToArray ());
-
- if (cm.ReturnType.BaseType == "System.Void")
- cm.Statements.Add (new CodeExpressionStatement (call));
- else
- cm.Statements.Add (new CodeMethodReturnStatement (call));
-
- // For async mode, add EndXxx() too.
if (!GenerateAsync)
- return;
+ continue;
+
+ cm = GenerateImplementationClientMethod (type, cd, od, true, out returnTypeFromMessageContract);
+ type.Members.Add (cm);
// EndXxx() implementation
if (od.EndMethod != null)
resultArgName = od.EndMethod.GetParameters () [0].Name;
- call = new CodeMethodInvokeExpression (
+ var call = new CodeMethodInvokeExpression (
new CodePropertyReferenceExpression (
new CodeBaseReferenceExpression (),
"Channel"),
}
}
+ CodeMemberMethod GenerateImplementationClientMethod (CodeTypeDeclaration type, ContractDescription cd, OperationDescription od, bool async, out CodeTypeReference returnTypeFromMessageContract)
+ {
+ CodeMemberMethod cm = new CodeMemberMethod ();
+ if (async)
+ cm.Name = "Begin" + od.Name;
+ else
+ cm.Name = od.Name;
+ cm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ returnTypeFromMessageContract = null;
+
+ List<CodeExpression> args = new List<CodeExpression> ();
+ if (od.SyncMethod != null) {
+ ParameterInfo [] pars = od.SyncMethod.GetParameters ();
+ ExportParameters (cm, pars);
+ cm.ReturnType = new CodeTypeReference (od.SyncMethod.ReturnType);
+ int i = 0;
+ foreach (ParameterInfo pi in pars)
+ args.Add (new CodeArgumentReferenceExpression (pi.Name));
+ } else {
+ args.AddRange (ExportMessages (od.Messages, cm, true));
+ returnTypeFromMessageContract = cm.ReturnType;
+ if (async) {
+ AddBeginAsyncArgs (cm);
+ cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
+ }
+ }
+ if (async) {
+ args.Add (new CodeArgumentReferenceExpression ("asyncCallback"));
+ args.Add (new CodeArgumentReferenceExpression ("userState"));
+ }
+
+ CodeExpression call = new CodeMethodInvokeExpression (
+ new CodePropertyReferenceExpression (
+ new CodeBaseReferenceExpression (),
+ "Channel"),
+ cm.Name,
+ args.ToArray ());
+
+ if (cm.ReturnType.BaseType == "System.Void")
+ cm.Statements.Add (new CodeExpressionStatement (call));
+ else
+ cm.Statements.Add (new CodeMethodReturnStatement (call));
+ return cm;
+ }
+
+ CodeMemberMethod FindByName (CodeTypeDeclaration type, string name)
+ {
+ foreach (var m in type.Members) {
+ var method = m as CodeMemberMethod;
+ if (method != null && method.Name == name)
+ return method;
+ }
+ return null;
+ }
+
+ void GenerateEventBasedAsyncSupport (CodeTypeDeclaration type, OperationDescription od, CodeNamespace cns)
+ {
+ var method = FindByName (type, od.Name) ?? FindByName (type, "Begin" + od.Name);
+ var endMethod = method.Name == od.Name ? null : FindByName (type, "End" + od.Name);
+ bool methodAsync = method.Name.StartsWith ("Begin", StringComparison.Ordinal);
+ var resultType = endMethod != null ? endMethod.ReturnType : method.ReturnType;
+
+ var thisExpr = new CodeThisReferenceExpression ();
+ var baseExpr = new CodeBaseReferenceExpression ();
+ var nullExpr = new CodePrimitiveExpression (null);
+ var asyncResultType = new CodeTypeReference (typeof (IAsyncResult));
+
+ // OnBeginXxx() implementation
+ var cm = new CodeMemberMethod () {
+ Name = "OnBegin" + od.Name,
+ Attributes = MemberAttributes.Private | MemberAttributes.Final,
+ ReturnType = asyncResultType
+ };
+ type.Members.Add (cm);
+
+ AddMethodParam (cm, typeof (object []), "args");
+ AddMethodParam (cm, typeof (AsyncCallback), "asyncCallback");
+ AddMethodParam (cm, typeof (object), "userState");
+
+ var call = new CodeMethodInvokeExpression (
+ thisExpr,
+ "Begin" + od.Name);
+ for (int idx = 0; idx < method.Parameters.Count - (methodAsync ? 2 : 0); idx++) {
+ var p = method.Parameters [idx];
+ cm.Statements.Add (new CodeVariableDeclarationStatement (p.Type, p.Name, new CodeCastExpression (p.Type, new CodeArrayIndexerExpression (new CodeArgumentReferenceExpression ("args"), new CodePrimitiveExpression (idx)))));
+ call.Parameters.Add (new CodeVariableReferenceExpression (p.Name));
+ }
+ call.Parameters.Add (new CodeArgumentReferenceExpression ("asyncCallback"));
+ call.Parameters.Add (new CodeArgumentReferenceExpression ("userState"));
+ cm.Statements.Add (new CodeMethodReturnStatement (call));
+
+ // OnEndXxx() implementation
+ cm = new CodeMemberMethod () {
+ Name = "OnEnd" + od.Name,
+ Attributes = MemberAttributes.Private | MemberAttributes.Final,
+ ReturnType = new CodeTypeReference (typeof (object [])) };
+ type.Members.Add (cm);
+
+ AddMethodParam (cm, typeof (IAsyncResult), "result");
+
+ var outArgRefs = new List<CodeVariableReferenceExpression> ();
+
+ for (int idx = 0; idx < method.Parameters.Count; idx++) {
+ var p = method.Parameters [idx];
+ if (p.Direction != FieldDirection.In) {
+ cm.Statements.Add (new CodeVariableDeclarationStatement (p.Type, p.Name));
+ outArgRefs.Add (new CodeVariableReferenceExpression (p.Name)); // FIXME: should this work? They need "out" or "ref" modifiers.
+ }
+ }
+
+ call = new CodeMethodInvokeExpression (
+ thisExpr,
+ "End" + od.Name,
+ new CodeArgumentReferenceExpression ("result"));
+ call.Parameters.AddRange (outArgRefs.Cast<CodeExpression> ().ToArray ()); // questionable
+
+ var retCreate = new CodeArrayCreateExpression (typeof (object));
+ if (resultType.BaseType == "System.Void")
+ cm.Statements.Add (call);
+ else {
+ cm.Statements.Add (new CodeVariableDeclarationStatement (typeof (object), "__ret", call));
+ retCreate.Initializers.Add (new CodeVariableReferenceExpression ("__ret"));
+ }
+ foreach (var outArgRef in outArgRefs)
+ retCreate.Initializers.Add (new CodeVariableReferenceExpression (outArgRef.VariableName));
+
+ cm.Statements.Add (new CodeMethodReturnStatement (retCreate));
+
+ // OnXxxCompleted() implementation
+ cm = new CodeMemberMethod () {
+ Name = "On" + od.Name + "Completed",
+ Attributes = MemberAttributes.Private | MemberAttributes.Final };
+ type.Members.Add (cm);
+
+ AddMethodParam (cm, typeof (object), "state");
+
+ string argsname = identifiers.AddUnique (od.Name + "CompletedEventArgs", null);
+ var iaargs = new CodeTypeReference ("InvokeAsyncCompletedEventArgs"); // avoid messy System.Type instance for generic nested type :|
+ var iaref = new CodeVariableReferenceExpression ("args");
+ var methodEventArgs = new CodeObjectCreateExpression (new CodeTypeReference (argsname),
+ new CodePropertyReferenceExpression (iaref, "Results"),
+ new CodePropertyReferenceExpression (iaref, "Error"),
+ new CodePropertyReferenceExpression (iaref, "Cancelled"),
+ new CodePropertyReferenceExpression (iaref, "UserState"));
+ cm.Statements.Add (new CodeConditionStatement (
+ new CodeBinaryOperatorExpression (
+ new CodeEventReferenceExpression (thisExpr, od.Name + "Completed"), CodeBinaryOperatorType.IdentityInequality, nullExpr),
+ new CodeVariableDeclarationStatement (iaargs, "args", new CodeCastExpression (iaargs, new CodeArgumentReferenceExpression ("state"))),
+ new CodeExpressionStatement (new CodeMethodInvokeExpression (thisExpr, od.Name + "Completed", thisExpr, methodEventArgs))));
+
+ // delegate fields
+ type.Members.Add (new CodeMemberField (new CodeTypeReference ("BeginOperationDelegate"), "onBegin" + od.Name + "Delegate"));
+ type.Members.Add (new CodeMemberField (new CodeTypeReference ("EndOperationDelegate"), "onEnd" + od.Name + "Delegate"));
+ type.Members.Add (new CodeMemberField (new CodeTypeReference (typeof (SendOrPostCallback)), "on" + od.Name + "CompletedDelegate"));
+
+ // XxxCompletedEventArgs class
+ var argsType = new CodeTypeDeclaration (argsname);
+ argsType.BaseTypes.Add (new CodeTypeReference (typeof (AsyncCompletedEventArgs)));
+ cns.Types.Add (argsType);
+
+ var argsCtor = new CodeConstructor () {
+ Attributes = MemberAttributes.Public | MemberAttributes.Final };
+ argsCtor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object []), "results"));
+ argsCtor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (Exception), "error"));
+ argsCtor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (bool), "cancelled"));
+ argsCtor.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "userState"));
+ argsCtor.BaseConstructorArgs.Add (new CodeArgumentReferenceExpression ("error"));
+ argsCtor.BaseConstructorArgs.Add (new CodeArgumentReferenceExpression ("cancelled"));
+ argsCtor.BaseConstructorArgs.Add (new CodeArgumentReferenceExpression ("userState"));
+ var resultsField = new CodeFieldReferenceExpression (thisExpr, "results");
+ argsCtor.Statements.Add (new CodeAssignStatement (resultsField, new CodeArgumentReferenceExpression ("results")));
+ argsType.Members.Add (argsCtor);
+
+ argsType.Members.Add (new CodeMemberField (typeof (object []), "results"));
+
+ if (resultType.BaseType != "System.Void") {
+ var resultProp = new CodeMemberProperty {
+ Name = "Result",
+ Type = resultType,
+ Attributes = MemberAttributes.Public | MemberAttributes.Final };
+ resultProp.GetStatements.Add (new CodeMethodReturnStatement (new CodeCastExpression (resultProp.Type, new CodeArrayIndexerExpression (resultsField, new CodePrimitiveExpression (0)))));
+ argsType.Members.Add (resultProp);
+ }
+
+ // event field
+ var handlerType = new CodeTypeReference (typeof (EventHandler<>));
+ handlerType.TypeArguments.Add (new CodeTypeReference (argsType.Name));
+ type.Members.Add (new CodeMemberEvent () {
+ Name = od.Name + "Completed",
+ Type = handlerType,
+ Attributes = MemberAttributes.Public | MemberAttributes.Final });
+
+ // XxxAsync() implementations
+ bool hasAsync = false;
+ foreach (int __x in Enumerable.Range (0, 2)) {
+ cm = new CodeMemberMethod ();
+ type.Members.Add (cm);
+ cm.Name = od.Name + "Async";
+ cm.Attributes = MemberAttributes.Public
+ | MemberAttributes.Final;
+
+ var inArgs = new List<CodeParameterDeclarationExpression > ();
+
+ for (int idx = 0; idx < method.Parameters.Count - (methodAsync ? 2 : 0); idx++) {
+ var pd = method.Parameters [idx];
+ inArgs.Add (pd);
+ cm.Parameters.Add (pd);
+ }
+
+ // First one is overload without asyncState arg.
+ if (!hasAsync) {
+ call = new CodeMethodInvokeExpression (thisExpr, cm.Name, inArgs.ConvertAll<CodeExpression> (decl => new CodeArgumentReferenceExpression (decl.Name)).ToArray ());
+ call.Parameters.Add (nullExpr);
+ cm.Statements.Add (new CodeExpressionStatement (call));
+ hasAsync = true;
+ continue;
+ }
+
+ // Second one is the primary one.
+
+ cm.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "userState"));
+
+ // if (onBeginBarOperDelegate == null) onBeginBarOperDelegate = new BeginOperationDelegate (OnBeginBarOper);
+ // if (onEndBarOperDelegate == null) onEndBarOperDelegate = new EndOperationDelegate (OnEndBarOper);
+ // if (onBarOperCompletedDelegate == null) onBarOperCompletedDelegate = new BeginOperationDelegate (OnBarOperCompleted);
+ var beginOperDelegateRef = new CodeFieldReferenceExpression (thisExpr, "onBegin" + od.Name + "Delegate");
+ var endOperDelegateRef = new CodeFieldReferenceExpression (thisExpr, "onEnd" + od.Name + "Delegate");
+ var operCompletedDelegateRef = new CodeFieldReferenceExpression (thisExpr, "on" + od.Name + "CompletedDelegate");
+
+ var ifstmt = new CodeConditionStatement (
+ new CodeBinaryOperatorExpression (beginOperDelegateRef, CodeBinaryOperatorType.IdentityEquality, nullExpr),
+ new CodeAssignStatement (beginOperDelegateRef, new CodeDelegateCreateExpression (new CodeTypeReference ("BeginOperationDelegate"), thisExpr, "OnBegin" + od.Name)));
+ cm.Statements.Add (ifstmt);
+ ifstmt = new CodeConditionStatement (
+ new CodeBinaryOperatorExpression (endOperDelegateRef, CodeBinaryOperatorType.IdentityEquality, nullExpr),
+ new CodeAssignStatement (endOperDelegateRef, new CodeDelegateCreateExpression (new CodeTypeReference ("EndOperationDelegate"), thisExpr, "OnEnd" + od.Name)));
+ cm.Statements.Add (ifstmt);
+ ifstmt = new CodeConditionStatement (
+ new CodeBinaryOperatorExpression (operCompletedDelegateRef, CodeBinaryOperatorType.IdentityEquality, nullExpr),
+ new CodeAssignStatement (operCompletedDelegateRef, new CodeDelegateCreateExpression (new CodeTypeReference (typeof (SendOrPostCallback)), thisExpr, "On" + od.Name + "Completed")));
+ cm.Statements.Add (ifstmt);
+
+ // InvokeAsync (onBeginBarOperDelegate, inValues, onEndBarOperDelegate, onBarOperCompletedDelegate, userState);
+
+ inArgs.Add (new CodeParameterDeclarationExpression (typeof (object), "userState"));
+
+ var args = new List<CodeExpression> ();
+ args.Add (beginOperDelegateRef);
+ args.Add (new CodeArrayCreateExpression (typeof (object), inArgs.ConvertAll<CodeExpression> (decl => new CodeArgumentReferenceExpression (decl.Name)).ToArray ()));
+ args.Add (endOperDelegateRef);
+ args.Add (new CodeFieldReferenceExpression (thisExpr, "on" + od.Name + "CompletedDelegate"));
+ args.Add (new CodeArgumentReferenceExpression ("userState"));
+ call = new CodeMethodInvokeExpression (baseExpr, "InvokeAsync", args.ToArray ());
+ cm.Statements.Add (new CodeExpressionStatement (call));
+ }
+ }
+
+ void AddMethodParam (CodeMemberMethod cm, Type type, string name)
+ {
+ cm.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (type), name));
+ }
+
+ const string ms_arrays_ns = "http://schemas.microsoft.com/2003/10/Serialization/Arrays";
+
private CodeExpression[] ExportMessages (MessageDescriptionCollection messages, CodeMemberMethod method, bool return_args)
{
CodeExpression [] args = null;
foreach (MessageDescription md in messages) {
if (md.Direction == MessageDirection.Output) {
if (md.Body.ReturnValue != null) {
- ExportDataContract (md.Body.ReturnValue.XmlTypeMapping);
- method.ReturnType = new CodeTypeReference (md.Body.ReturnValue.TypeName.Name);
+ ExportDataContract (md.Body.ReturnValue);
+ method.ReturnType = md.Body.ReturnValue.CodeTypeReference;
}
continue;
}
MessagePartDescriptionCollection parts = md.Body.Parts;
for (int i = 0; i < parts.Count; i++) {
- ExportDataContract (parts [i].XmlTypeMapping);
+ ExportDataContract (parts [i]);
method.Parameters.Add (
new CodeParameterDeclarationExpression (
- new CodeTypeReference (parts [i].TypeName.Name),
+ parts [i].CodeTypeReference,
parts [i].Name));
if (return_args)
#endregion
- [MonoTODO]
public CodeTypeReference GenerateServiceEndpoint (
ServiceEndpoint endpoint,
out ChannelEndpointElement channelElement)
{
- throw new NotImplementedException ();
- }
-
- private void ExportDataContract (XmlTypeMapping mapping)
- {
- if (mapping == null)
- return;
-
- QName qname = new QName (mapping.TypeName, mapping.Namespace);
- if (imported_names.ContainsKey (qname))
- return;
+ if (config == null)
+ throw new InvalidOperationException ();
- CodeNamespace cns = new CodeNamespace ();
+ var cd = endpoint.Contract;
+ var cns = GetNamespace (cd.Namespace);
+ var cache = ExportInterface_internal (cd, cns);
- XmlCodeExporter xce = new XmlCodeExporter (cns);
- xce.ExportTypeMapping (mapping);
+ string bindingSectionName, configurationName;
+ GenerateBinding (endpoint.Binding, out bindingSectionName, out configurationName);
- List <CodeTypeDeclaration> to_remove = new List <CodeTypeDeclaration> ();
-
- //Process the types just generated
- //FIXME: Iterate and assign the types to correct namespaces
- //At the end, add all those namespaces to the ccu
- foreach (CodeTypeDeclaration type in cns.Types) {
- string ns = GetXmlNamespace (type);
- if (ns == null)
- //FIXME: do what here?
- continue;
-
- QName type_name = new QName (type.Name, ns);
- if (imported_names.ContainsKey (type_name)) {
- //Type got reemitted, so remove it!
- to_remove.Add (type);
- continue;
- }
+ channelElement = new ChannelEndpointElement ();
+ channelElement.Binding = bindingSectionName;
+ channelElement.BindingConfiguration = configurationName;
+ channelElement.Name = configurationName;
+ channelElement.Contract = cache.ConfigurationName;
+ channelElement.Address = endpoint.Address.Uri;
- imported_names [type_name] = type_name;
+ var section = (ClientSection)config.GetSection ("system.serviceModel/client");
+ section.Endpoints.Add (channelElement);
- type.Comments.Clear ();
- //Custom Attributes
- type.CustomAttributes.Clear ();
+ return cache.GetReference ();
+ }
- if (type.IsEnum)
- continue;
-
- type.CustomAttributes.Add (
- new CodeAttributeDeclaration (
- new CodeTypeReference ("System.CodeDom.Compiler.GeneratedCodeAttribute"),
- new CodeAttributeArgument (new CodePrimitiveExpression ("System.Runtime.Serialization")),
- new CodeAttributeArgument (new CodePrimitiveExpression ("3.0.0.0"))));
-
- type.CustomAttributes.Add (
- new CodeAttributeDeclaration (
- new CodeTypeReference ("System.Runtime.Serialization.DataContractAttribute")));
-
- //BaseType and interface
- type.BaseTypes.Add (new CodeTypeReference (typeof (object)));
- type.BaseTypes.Add (new CodeTypeReference ("System.Runtime.Serialization.IExtensibleDataObject"));
-
- foreach (CodeTypeMember mbr in type.Members) {
- CodeMemberProperty p = mbr as CodeMemberProperty;
- if (p == null)
- continue;
-
- if ((p.Attributes & MemberAttributes.Public) == MemberAttributes.Public) {
- //FIXME: Clear all attributes or only XmlElementAttribute?
- p.CustomAttributes.Clear ();
- p.CustomAttributes.Add (new CodeAttributeDeclaration (
- new CodeTypeReference ("System.Runtime.Serialization.DataMemberAttribute")));
-
- p.Comments.Clear ();
+ void MergeCompileUnit (CodeCompileUnit from, CodeCompileUnit to)
+ {
+ if (from == to)
+ return;
+ foreach (CodeNamespace fns in from.Namespaces) {
+ bool merged = false;
+ foreach (CodeNamespace tns in to.Namespaces)
+ if (fns.Name == tns.Name) {
+ // namespaces are merged.
+ MergeNamespace (fns, tns);
+ merged = true;
+ break;
}
- }
-
- //Fields
- CodeMemberField field = new CodeMemberField (
- new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject"),
- "extensionDataField");
- field.Attributes = MemberAttributes.Private | MemberAttributes.Final;
- type.Members.Add (field);
-
- //Property
- CodeMemberProperty prop = new CodeMemberProperty ();
- prop.Type = new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject");
- prop.Name = "ExtensionData";
- prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
-
- //Get
- prop.GetStatements.Add (new CodeMethodReturnStatement (
- new CodeFieldReferenceExpression (
- new CodeThisReferenceExpression (),
- "extensionDataField")));
-
- //Set
- prop.SetStatements.Add (new CodeAssignStatement (
- new CodeFieldReferenceExpression (
- new CodeThisReferenceExpression (),
- "extensionDataField"),
- new CodePropertySetValueReferenceExpression ()));
-
- type.Members.Add (prop);
+ if (!merged)
+ to.Namespaces.Add (fns);
}
+ }
- foreach (CodeTypeDeclaration type in to_remove)
- cns.Types.Remove (type);
+ // existing type is skipped.
+ void MergeNamespace (CodeNamespace from, CodeNamespace to)
+ {
+ foreach (CodeTypeDeclaration ftd in from.Types) {
+ bool skip = false;
+ foreach (CodeTypeDeclaration ttd in to.Types)
+ if (ftd.Name == ttd.Name) {
+ skip = true;
+ break;
+ }
+ if (!skip)
+ to.Types.Add (ftd);
+ }
+ }
- ccu.Namespaces.Add (cns);
+ private void ExportDataContract (MessagePartDescription md)
+ {
+ if (data_contract_importer == null)
+ data_contract_importer = md.DataContractImporter;
+ else if (md.DataContractImporter != null && data_contract_importer != md.DataContractImporter)
+ throw new Exception ("INTERNAL ERROR: should not happen");
+ if (xml_serialization_importer == null)
+ xml_serialization_importer = md.XmlSerializationImporter;
+ else if (md.XmlSerializationImporter != null && xml_serialization_importer != md.XmlSerializationImporter)
+ throw new Exception ("INTERNAL ERROR: should not happen");
}
private string GetXmlNamespace (CodeTypeDeclaration type)