2010-01-28 Atsushi Enomoto <atsushi@ximian.com>
authorAtsushi Eno <atsushieno@gmail.com>
Thu, 28 Jan 2010 11:41:47 +0000 (11:41 -0000)
committerAtsushi Eno <atsushieno@gmail.com>
Thu, 28 Jan 2010 11:41:47 +0000 (11:41 -0000)
* ServiceContractGenerator.cs : when Options.AsynchronousMethods is
  specified, generate async methods *as well as* sync methods (i.e.
  not exclusively).

  In moonlight proxy generator (svcutil -moonlight) mode, sync
  methods will be removed at svcutil itself.
  This fix brings sync proxy methods back to monotouch.

* ServiceContractGeneratorTest.cs : add test for async method
  generation option to generate sync methods as well.

svn path=/trunk/mcs/; revision=150363

mcs/class/System.ServiceModel/System.ServiceModel.Description/ChangeLog
mcs/class/System.ServiceModel/System.ServiceModel.Description/ServiceContractGenerator.cs
mcs/class/System.ServiceModel/Test/System.ServiceModel.Description/ChangeLog
mcs/class/System.ServiceModel/Test/System.ServiceModel.Description/ServiceContractGeneratorTest.cs

index 7ce46c99dda612d5577a184e997e7bfa6f0dab7f..d4ec79c11028e86db33fc9242a0cc9492363d59a 100644 (file)
@@ -1,3 +1,13 @@
+2010-01-28  Atsushi Enomoto  <atsushi@ximian.com>
+
+       * ServiceContractGenerator.cs : when Options.AsynchronousMethods is
+         specified, generate async methods *as well as* sync methods (i.e.
+         not exclusively).
+
+         In moonlight proxy generator (svcutil -moonlight) mode, sync
+         methods will be removed at svcutil itself.
+         This fix brings sync proxy methods back to monotouch.
+
 2010-01-19  Atsushi Enomoto  <atsushi@ximian.com>
 
        * ServiceAuthorizationBehavior.cs : implement (it does almost
index f63703a346bf84e97a8970a57ebd02c9d7f69404..459813ebfd3c29ce38afdfa15879e53abcfab302 100644 (file)
@@ -320,53 +320,15 @@ namespace System.ServiceModel.Description
                        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;
@@ -388,6 +350,48 @@ namespace System.ServiceModel.Description
                        }
                }
 
+               CodeMemberMethod GenerateOperationMethod (CodeTypeDeclaration type, ContractDescription cd, OperationDescription od, bool async, out CodeTypeReference returnType)
+               {
+                       CodeMemberMethod cm = new CodeMemberMethod ();
+
+                       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)
@@ -400,53 +404,17 @@ namespace System.ServiceModel.Description
                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)
                                        continue;
 
+                               cm = GenerateImplementationClientMethod (type, cd, od, true, out returnTypeFromMessageContract);
+                               type.Members.Add (cm);
+
                                // EndXxx() implementation
 
                                cm = new CodeMemberMethod ();
@@ -467,7 +435,7 @@ namespace System.ServiceModel.Description
                                if (od.EndMethod != null)
                                        resultArgName = od.EndMethod.GetParameters () [0].Name;
 
-                               call = new CodeMethodInvokeExpression (
+                               var call = new CodeMethodInvokeExpression (
                                        new CodePropertyReferenceExpression (
                                                new CodeBaseReferenceExpression (),
                                                "Channel"),
@@ -481,6 +449,51 @@ namespace System.ServiceModel.Description
                        }
                }
 
+               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) {
index e315e2b9f6f7cb210b117e31ed933bc1989a6f46..4ca4eb10249265b4beb84fd74e85637452fc7b28 100755 (executable)
@@ -1,3 +1,8 @@
+2010-01-28  Atsushi Enomoto  <atsushi@ximian.com>
+
+       * ServiceContractGeneratorTest.cs : add test for async method
+         generation option to generate sync methods as well.
+
 2010-01-22  Atsushi Enomoto  <atsushi@ximian.com>
 
        * ServiceMetadataBehaviorTest.cs : check name constant (MSDN is
index ca9de9a784e633f8d5b1ab8a7376b13cb50fc031..1c95591ac9224676596d865836933c2fda8041a1 100644 (file)
@@ -49,6 +49,15 @@ namespace MonoTests.System.ServiceModel.Description
                                        return t;
                        return default (T);
                }
+
+               public static int Count<T> (this CollectionBase coll, Func<T,bool> func)
+               {
+                       int c = 0;
+                       foreach (T t in coll)
+                               if (func (t))
+                                       c++;
+                       return c;
+               }
        }
 
        [TestFixture]
@@ -62,11 +71,41 @@ namespace MonoTests.System.ServiceModel.Description
                        var cns = g.TargetCompileUnit.Namespaces [0];
                        Assert.AreEqual (3, cns.Types.Count, "#1");
                        var iface = cns.Types.FirstOrDefault<CodeTypeDeclaration> (t => t.Name == "ITestService");
+                       Assert.AreEqual (2, iface.Members.Count, "#2-0");
+                       Assert.IsNotNull (iface.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "DoWork"), "#2-1");
+                       Assert.IsNotNull (iface.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "DoWork2"), "#2-2");
+                       var proxy = cns.Types.FirstOrDefault<CodeTypeDeclaration> (t => t.Name == "TestServiceClient");
+                       Assert.AreEqual (7, proxy.Members.Count, "#3-0");
+                       Assert.AreEqual (5, proxy.Members.Count<CodeTypeMember> (m => m.Name == ".ctor"), "#3-0-2");
+                       Assert.IsNotNull (proxy.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "DoWork"), "#3-1");
+                       Assert.IsNotNull (proxy.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "DoWork2"), "#3-2");
+               }
+
+               [Test]
+               public void AsynchronousMethods ()
+               {
+                       var g = new ServiceContractGenerator ();
+                       g.Options |= ServiceContractGenerationOptions.AsynchronousMethods;
+                       g.GenerateServiceContractType (ContractDescription.GetContract (typeof (ITestService)));
+                       var cns = g.TargetCompileUnit.Namespaces [0];
+                       Assert.AreEqual (3, cns.Types.Count, "#1");
+                       var iface = cns.Types.FirstOrDefault<CodeTypeDeclaration> (t => t.Name == "ITestService");
+                       Assert.AreEqual (6, iface.Members.Count, "#2-0");
                        Assert.IsNotNull (iface.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "DoWork"), "#2-1");
                        Assert.IsNotNull (iface.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "DoWork2"), "#2-2");
+                       Assert.IsNotNull (iface.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "BeginDoWork"), "#2-3");
+                       Assert.IsNotNull (iface.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "BeginDoWork2"), "#2-4");
+                       Assert.IsNotNull (iface.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "EndDoWork"), "#2-5");
+                       Assert.IsNotNull (iface.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "EndDoWork2"), "#2-6");
                        var proxy = cns.Types.FirstOrDefault<CodeTypeDeclaration> (t => t.Name == "TestServiceClient");
+                       Assert.AreEqual (11, proxy.Members.Count, "#3-0");
+                       Assert.AreEqual (5, proxy.Members.Count<CodeTypeMember> (m => m.Name == ".ctor"), "#3-0-2");
                        Assert.IsNotNull (proxy.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "DoWork"), "#3-1");
                        Assert.IsNotNull (proxy.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "DoWork2"), "#3-2");
+                       Assert.IsNotNull (proxy.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "BeginDoWork"), "#3-3");
+                       Assert.IsNotNull (proxy.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "BeginDoWork2"), "#3-4");
+                       Assert.IsNotNull (proxy.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "EndDoWork"), "#3-5");
+                       Assert.IsNotNull (proxy.Members.FirstOrDefault<CodeTypeMember> (m => m.Name == "EndDoWork2"), "#3-6");
                }
 
                [ServiceContract]