Async task (#25)

Support for async/await. 
diff --git a/core/dotnet2.2/CHANGELOG.md b/core/dotnet2.2/CHANGELOG.md
index c530536..dfa57a4 100644
--- a/core/dotnet2.2/CHANGELOG.md
+++ b/core/dotnet2.2/CHANGELOG.md
@@ -23,3 +23,15 @@
 ## 1.13
 Changes:
 - Initial release
+
+## Release TBD
+Changes:
+- Support for async methods. Example:
+
+```csharp
+        public async Task<JObject> MainAsync(JObject args)
+        {
+            await Task.Delay(10); // Just do a delay to have an async/await process occur.
+            return (args);
+        }
+```
diff --git a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
index f5d9489..55a637f 100644
--- a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
+++ b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
@@ -33,6 +33,7 @@
         private Type Type { get; set; }
         private MethodInfo Method { get; set; }
         private ConstructorInfo Constructor { get; set; }
+        private bool AwaitableMethod { get; set; }
 
         public Init()
         {
@@ -51,7 +52,7 @@
                 {
                     await httpContext.Response.WriteError("Cannot initialize the action more than once.");
                     Console.Error.WriteLine("Cannot initialize the action more than once.");
-                    return (new Run(Type, Method, Constructor));
+                    return (new Run(Type, Method, Constructor, AwaitableMethod));
                 }
 
                 string body = await new StreamReader(httpContext.Request.Body).ReadToEndAsync();
@@ -156,7 +157,9 @@
 
                 await httpContext.Response.WriteResponse(200, "OK");
 
-                return (new Run(Type, Method, Constructor));
+                AwaitableMethod = (Method.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null);
+
+                return (new Run(Type, Method, Constructor, AwaitableMethod));
             }
             catch (Exception ex)
             {
diff --git a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
index 1ee35bb..21c94f0 100644
--- a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
+++ b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
@@ -29,12 +29,14 @@
         private readonly Type _type;
         private readonly MethodInfo _method;
         private readonly ConstructorInfo _constructor;
+        private readonly bool _awaitableMethod;
 
-        public Run(Type type, MethodInfo method, ConstructorInfo constructor)
+        public Run(Type type, MethodInfo method, ConstructorInfo constructor, bool awaitableMethod)
         {
             _type = type;
             _method = method;
             _constructor = constructor;
+            _awaitableMethod = awaitableMethod;
         }
 
         public async Task HandleRequest(HttpContext httpContext)
@@ -79,7 +81,14 @@
 
                 try
                 {
-                    JObject output = (JObject) _method.Invoke(owObject, new object[] {valObject});
+                    JObject output;
+                    
+                    if(_awaitableMethod) {
+                        output = (JObject) await (dynamic) _method.Invoke(owObject, new object[] {valObject});
+                    }
+                    else {
+                        output = (JObject) _method.Invoke(owObject, new object[] {valObject});
+                    }
 
                     if (output == null)
                     {
diff --git a/core/dotnet3.0/CHANGELOG.md b/core/dotnet3.0/CHANGELOG.md
index 9339dd7..c09bde8 100644
--- a/core/dotnet3.0/CHANGELOG.md
+++ b/core/dotnet3.0/CHANGELOG.md
@@ -20,6 +20,15 @@
 # .NET Core 3.0 OpenWhisk Runtime Container
 
 
-## 1.14 (next Apache release)
+## Release TBD
 Changes:
 - Initial release
+- Support for async methods. Example:
+
+```csharp
+        public async Task<JObject> MainAsync(JObject args)
+        {
+            await Task.Delay(10); // Just do a delay to have an async/await process occur.
+            return (args);
+        }
+```
diff --git a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
index f5d9489..55a637f 100644
--- a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
+++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
@@ -33,6 +33,7 @@
         private Type Type { get; set; }
         private MethodInfo Method { get; set; }
         private ConstructorInfo Constructor { get; set; }
+        private bool AwaitableMethod { get; set; }
 
         public Init()
         {
@@ -51,7 +52,7 @@
                 {
                     await httpContext.Response.WriteError("Cannot initialize the action more than once.");
                     Console.Error.WriteLine("Cannot initialize the action more than once.");
-                    return (new Run(Type, Method, Constructor));
+                    return (new Run(Type, Method, Constructor, AwaitableMethod));
                 }
 
                 string body = await new StreamReader(httpContext.Request.Body).ReadToEndAsync();
@@ -156,7 +157,9 @@
 
                 await httpContext.Response.WriteResponse(200, "OK");
 
-                return (new Run(Type, Method, Constructor));
+                AwaitableMethod = (Method.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null);
+
+                return (new Run(Type, Method, Constructor, AwaitableMethod));
             }
             catch (Exception ex)
             {
diff --git a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
index 1ee35bb..21c94f0 100644
--- a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
+++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
@@ -29,12 +29,14 @@
         private readonly Type _type;
         private readonly MethodInfo _method;
         private readonly ConstructorInfo _constructor;
+        private readonly bool _awaitableMethod;
 
-        public Run(Type type, MethodInfo method, ConstructorInfo constructor)
+        public Run(Type type, MethodInfo method, ConstructorInfo constructor, bool awaitableMethod)
         {
             _type = type;
             _method = method;
             _constructor = constructor;
+            _awaitableMethod = awaitableMethod;
         }
 
         public async Task HandleRequest(HttpContext httpContext)
@@ -79,7 +81,14 @@
 
                 try
                 {
-                    JObject output = (JObject) _method.Invoke(owObject, new object[] {valObject});
+                    JObject output;
+                    
+                    if(_awaitableMethod) {
+                        output = (JObject) await (dynamic) _method.Invoke(owObject, new object[] {valObject});
+                    }
+                    else {
+                        output = (JObject) _method.Invoke(owObject, new object[] {valObject});
+                    }
 
                     if (output == null)
                     {
diff --git a/tests/dotnetshared/Echo.cs b/tests/dotnetshared/Echo.cs
index ba39177..29f1a33 100644
--- a/tests/dotnetshared/Echo.cs
+++ b/tests/dotnetshared/Echo.cs
@@ -17,6 +17,7 @@
 
 using System;
 using Newtonsoft.Json.Linq;
+using System.Threading.Tasks;
 
 namespace Apache.OpenWhisk.Tests.Dotnet
 {
@@ -26,5 +27,11 @@
         {
             return (args);
         }
+
+        public async Task<JObject> MainAsync(JObject args)
+        {
+            await Task.Delay(10); // Just do a delay to have an async/await process occur.
+            return (args);
+        }
     }
 }
diff --git a/tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala b/tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala
index 6f84f75..bea113b 100644
--- a/tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala
+++ b/tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala
@@ -52,7 +52,7 @@
   }
 
   val testEchoNoWrite = {
-    TestConfig(functionb64, main = "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Echo::Main")
+    TestConfig(functionb64, main = "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Echo::MainAsync")
   }
 
   override val testUnicode = {
diff --git a/tests/src/test/scala/actionContainers/DotNet3_0ActionContainerTests.scala b/tests/src/test/scala/actionContainers/DotNet3_0ActionContainerTests.scala
index ec937ab..d05860c 100644
--- a/tests/src/test/scala/actionContainers/DotNet3_0ActionContainerTests.scala
+++ b/tests/src/test/scala/actionContainers/DotNet3_0ActionContainerTests.scala
@@ -52,7 +52,7 @@
   }
 
   val testEchoNoWrite = {
-    TestConfig(functionb64, main = "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Echo::Main")
+    TestConfig(functionb64, main = "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Echo::MainAsync")
   }
 
   override val testUnicode = {